Import Cobalt 13.101483
Change-Id: Ie3cc107cc4c8d9cc0552d1d34835e860f6ee8521
diff --git a/src/base/atomicops.h b/src/base/atomicops.h
index 4b2f4da..97db317 100644
--- a/src/base/atomicops.h
+++ b/src/base/atomicops.h
@@ -60,7 +60,15 @@
// Use AtomicWord for a machine-sized pointer. It will use the Atomic32 or
// Atomic64 routines below, depending on your architecture.
+#if defined(OS_STARBOARD)
+#if SB_HAS(64_BIT_POINTERS)
+typedef SbAtomic64 AtomicWord;
+#else
+typedef SbAtomic32 AtomicWord;
+#endif
+#else
typedef intptr_t AtomicWord;
+#endif
// Atomically execute:
// result = *ptr;
diff --git a/src/base/basictypes.h b/src/base/basictypes.h
index c393fd7..c903434 100644
--- a/src/base/basictypes.h
+++ b/src/base/basictypes.h
@@ -11,6 +11,10 @@
#include "base/port.h" // Types that only need exist on certain systems
+#if defined(OS_STARBOARD)
+#include "starboard/types.h"
+#endif // defined(OS_STARBOARD)
+
#ifndef COMPILER_MSVC
// stdint.h is part of C99 but MSVC doesn't have it.
#include <stdint.h> // For intptr_t.
@@ -19,8 +23,15 @@
typedef signed char schar;
typedef signed char int8;
typedef short int16;
+#if defined(OS_STARBOARD)
+typedef int32_t int32;
+#else
typedef int int32;
+#endif // defined(OS_STARBOARD)
+#if defined(OS_STARBOARD)
+typedef int64_t int64;
+#else
// The NSPR system headers define 64-bit as |long| when possible, except on
// Mac OS X. In order to not have typedef mismatches, we do the same on LP64.
//
@@ -31,6 +42,7 @@
#else
typedef long long int64;
#endif
+#endif // defined(OS_STARBOARD)
// NOTE: unsigned types are DANGEROUS in loops and other arithmetical
// places. Use the signed types unless your variable represents a bit
@@ -38,22 +50,37 @@
// use 'unsigned' to express "this value should always be positive";
// use assertions for this.
+#if defined(OS_STARBOARD)
+typedef uint8_t uint8;
+typedef uint16_t uint16;
+typedef uint32_t uint32;
+#else
typedef unsigned char uint8;
typedef unsigned short uint16;
typedef unsigned int uint32;
+#endif // defined(OS_STARBOARD)
+#if defined(OS_STARBOARD)
+typedef uint64_t uint64;
+#else
// See the comment above about NSPR and 64-bit.
#if defined(__LP64__) && !defined(OS_MACOSX) && !defined(OS_OPENBSD)
typedef unsigned long uint64;
#else
typedef unsigned long long uint64;
#endif
+#endif // defined(OS_STARBOARD)
// A type to represent a Unicode code-point value. As of Unicode 4.0,
// such values require up to 21 bits.
// (For type-checking on pointers, make this explicitly signed,
// and it should always be the signed version of whatever int32 is.)
-typedef signed int char32;
+#if defined(OS_STARBOARD)
+typedef int32_t char32;
+#else
+typedef signed int char32;
+#endif // defined(OS_STARBOARD)
+
#if defined(COBALT_WIN)
#pragma warning(push)
diff --git a/src/cobalt/accessibility/screen_reader_tests.cc b/src/cobalt/accessibility/screen_reader_tests.cc
index 9adc74d..714f243 100644
--- a/src/cobalt/accessibility/screen_reader_tests.cc
+++ b/src/cobalt/accessibility/screen_reader_tests.cc
@@ -101,6 +101,10 @@
quit_event_.Signal();
screen_reader_.reset();
}
+ void OnClose(base::TimeDelta close_time) {
+ UNREFERENCED_PARAMETER(close_time);
+ Quit();
+ }
scoped_refptr<script::Wrappable> CreateWindowAttribute(
const scoped_refptr<dom::Window>& window,
@@ -167,7 +171,7 @@
url, base::kApplicationStateStarted,
base::Bind(&LiveRegionMutationTest::OnRenderTreeProducedStub),
base::Bind(&LiveRegionMutationTest::OnError, base::Unretained(this)),
- base::Bind(&LiveRegionMutationTest::Quit, base::Unretained(this)),
+ base::Bind(&LiveRegionMutationTest::OnClose, base::Unretained(this)),
base::Closure(), /* window_minimize_callback */
NULL /* media_module */, &network_module, kDefaultViewportSize,
kDefaultVideoPixelRatio, &resource_provider, kRefreshRate,
diff --git a/src/cobalt/bindings/testing/bindings_sandbox_main.cc b/src/cobalt/bindings/testing/bindings_sandbox_main.cc
index 0b73fa9..30f7e25 100644
--- a/src/cobalt/bindings/testing/bindings_sandbox_main.cc
+++ b/src/cobalt/bindings/testing/bindings_sandbox_main.cc
@@ -27,8 +27,9 @@
int SandboxMain(int argc, char** argv) {
scoped_refptr<Window> test_window = new Window();
- cobalt::script::JavaScriptEngine::Options js_options;
- StandaloneJavascriptRunner standalone_runner(js_options, test_window);
+ cobalt::script::JavaScriptEngine::Options javascript_engine_options;
+ StandaloneJavascriptRunner standalone_runner(javascript_engine_options,
+ test_window);
standalone_runner.RunInteractive();
return 0;
}
diff --git a/src/cobalt/browser/application.cc b/src/cobalt/browser/application.cc
index 0d7d821..ba9db81 100644
--- a/src/cobalt/browser/application.cc
+++ b/src/cobalt/browser/application.cc
@@ -378,19 +378,6 @@
#endif
"h5vcc:";
-#if !defined(COBALT_FORCE_CSP)
-dom::CspEnforcementType StringToCspMode(const std::string& mode) {
- if (mode == "disable") {
- return dom::kCspEnforcementDisable;
- } else if (mode == "enable") {
- return dom::kCspEnforcementEnable;
- } else {
- DLOG(INFO) << "Invalid CSP mode: " << mode << ": use [disable|enable]";
- return dom::kCspEnforcementEnable;
- }
-}
-#endif // !defined(COBALT_FORCE_CSP)
-
struct NonTrivialStaticFields {
NonTrivialStaticFields() : system_language(base::GetSystemLanguage()) {}
@@ -401,6 +388,11 @@
DISALLOW_COPY_AND_ASSIGN(NonTrivialStaticFields);
};
+struct SecurityFlags {
+ csp::CSPHeaderPolicy csp_header_policy;
+ network::HTTPSRequirement https_requirement;
+};
+
// |non_trivial_static_fields| will be lazily created on the first time it's
// accessed.
base::LazyInstance<NonTrivialStaticFields> non_trivial_static_fields =
@@ -493,7 +485,7 @@
ApplyCommandLineSettingsToRendererOptions(&options.renderer_module_options);
if (command_line->HasSwitch(browser::switches::kDisableJavaScriptJit)) {
- options.web_module_options.javascript_options.disable_jit = true;
+ options.web_module_options.javascript_engine_options.disable_jit = true;
}
#if defined(ENABLE_DEBUG_COMMAND_LINE_SWITCHES)
@@ -516,6 +508,7 @@
// User can specify an extra search path entry for files loaded via file://.
options.web_module_options.extra_web_file_dir = GetExtraWebFileDir();
+ SecurityFlags security_flags{csp::kCSPRequired, network::kHTTPSRequired};
options.web_module_options.location_policy = kYouTubeTvLocationPolicy;
// Set callback to be notified when a navigation occurs that destroys the
// underlying WebModule.
@@ -531,29 +524,24 @@
command_line->GetSwitchValueASCII(browser::switches::kProxy);
}
-#if !defined(COBALT_FORCE_CSP)
- if (command_line->HasSwitch(browser::switches::kCspMode)) {
- options.web_module_options.csp_enforcement_mode = StringToCspMode(
- command_line->GetSwitchValueASCII(browser::switches::kCspMode));
- }
- if (options.web_module_options.csp_enforcement_mode !=
- dom::kCspEnforcementEnable) {
- options.web_module_options.location_policy = "h5vcc-location-src *";
- }
-#endif // !defined(COBALT_FORCE_CSP)
-
#if defined(ENABLE_IGNORE_CERTIFICATE_ERRORS)
if (command_line->HasSwitch(browser::switches::kIgnoreCertificateErrors)) {
options.network_module_options.ignore_certificate_errors = true;
}
#endif // defined(ENABLE_IGNORE_CERTIFICATE_ERRORS)
-#if !defined(COBALT_FORCE_HTTPS)
- if (command_line->HasSwitch(switches::kAllowHttp)) {
- DLOG(INFO) << "Allowing insecure HTTP connections";
- options.network_module_options.require_https = false;
+ if (!command_line->HasSwitch(switches::kRequireHTTPSLocation)) {
+ security_flags.https_requirement = network::kHTTPSOptional;
}
-#endif // !defined(COBALT_FORCE_HTTPS)
+
+ if (!command_line->HasSwitch(browser::switches::kRequireCSP)) {
+ security_flags.csp_header_policy = csp::kCSPOptional;
+ }
+
+ if (command_line->HasSwitch(browser::switches::kProd)) {
+ security_flags.https_requirement = network::kHTTPSRequired;
+ security_flags.csp_header_policy = csp::kCSPRequired;
+ }
if (command_line->HasSwitch(switches::kVideoPlaybackRateMultiplier)) {
double playback_rate = 1.0;
@@ -598,6 +586,20 @@
}
#endif // ENABLE_DEBUG_COMMAND_LINE_SWITCHES
+// Production-builds override all switches to the most secure configuration.
+#if defined(COBALT_FORCE_HTTPS)
+ security_flags.https_requirement = network::kHTTPSRequired;
+#endif // defined(COBALT_FORCE_HTTPS)
+
+#if defined(COBALT_FORCE_CSP)
+ security_flags.csp_header_policy = csp::kCSPRequired;
+#endif // defined(COBALT_FORCE_CSP)
+
+ options.network_module_options.https_requirement =
+ security_flags.https_requirement;
+ options.web_module_options.require_csp = security_flags.csp_header_policy;
+ options.web_module_options.csp_enforcement_mode = dom::kCspEnforcementEnable;
+
if (command_line->HasSwitch(browser::switches::kDisableNavigationWhitelist)) {
LOG(ERROR) << "\n"
<< " *** Disabling the default navigation whitelist! ***\n"
diff --git a/src/cobalt/browser/browser_module.cc b/src/cobalt/browser/browser_module.cc
index 31ab25d..1a0f89a 100644
--- a/src/cobalt/browser/browser_module.cc
+++ b/src/cobalt/browser/browser_module.cc
@@ -257,7 +257,10 @@
will_quit_(false),
application_state_(initial_application_state),
splash_screen_cache_(new SplashScreenCache()),
- navigation_produced_main_render_tree_(false) {
+ main_web_module_generation_(0),
+ next_timeline_id_(1),
+ current_splash_screen_timeline_id_(-1),
+ current_main_web_module_timeline_id_(-1) {
h5vcc_url_handler_.reset(new H5vccURLHandler(this));
#if SB_HAS(CORE_DUMP_HANDLER_SUPPORT)
@@ -328,7 +331,7 @@
&network_module_, GetViewportSize(), GetResourceProvider(),
kLayoutMaxRefreshFrequencyInHz,
base::Bind(&BrowserModule::GetDebugServer, base::Unretained(this)),
- options_.web_module_options.javascript_options));
+ options_.web_module_options.javascript_engine_options));
lifecycle_observers_.AddObserver(debug_console_.get());
#endif // defined(ENABLE_DEBUG_CONSOLE)
@@ -392,6 +395,14 @@
}
web_module_.reset(NULL);
+ // Increment the navigation generation so that we can attach it to event
+ // callbacks as a way of identifying the new web module from the old ones.
+ ++main_web_module_generation_;
+ current_splash_screen_timeline_id_ = next_timeline_id_++;
+ current_main_web_module_timeline_id_ = next_timeline_id_++;
+
+ main_web_module_layer_->Reset();
+
// Wait until after the old WebModule is destroyed before setting the navigate
// time so that it won't be included in the time taken to load the URL.
navigate_time_ = base::TimeTicks::Now().ToInternalValue();
@@ -399,8 +410,7 @@
// Show a splash screen while we're waiting for the web page to load.
const math::Size& viewport_size = GetViewportSize();
- DestroySplashScreen();
- navigation_produced_main_render_tree_ = false;
+ DestroySplashScreen(base::TimeDelta());
base::optional<std::string> key = SplashScreenCache::GetKeyForStartUrl(url);
if (fallback_splash_screen_url_ ||
(key && splash_screen_cache_->IsSplashScreenCached(*key))) {
@@ -459,7 +469,7 @@
web_module_.reset(new WebModule(
url, application_state_,
base::Bind(&BrowserModule::QueueOnRenderTreeProduced,
- base::Unretained(this)),
+ base::Unretained(this), main_web_module_generation_),
base::Bind(&BrowserModule::OnError, base::Unretained(this)),
base::Bind(&BrowserModule::OnWindowClose, base::Unretained(this)),
base::Bind(&BrowserModule::OnWindowMinimize, base::Unretained(this)),
@@ -544,11 +554,12 @@
}
void BrowserModule::QueueOnRenderTreeProduced(
+ int main_web_module_generation,
const browser::WebModule::LayoutResults& layout_results) {
TRACE_EVENT0("cobalt::browser", "BrowserModule::QueueOnRenderTreeProduced()");
render_tree_submission_queue_.AddMessage(
base::Bind(&BrowserModule::OnRenderTreeProduced, base::Unretained(this),
- layout_results));
+ main_web_module_generation, layout_results));
self_message_loop_->PostTask(
FROM_HERE,
base::Bind(&BrowserModule::ProcessRenderTreeSubmissionQueue, weak_this_));
@@ -567,11 +578,18 @@
}
void BrowserModule::OnRenderTreeProduced(
+ int main_web_module_generation,
const browser::WebModule::LayoutResults& layout_results) {
TRACE_EVENT0("cobalt::browser", "BrowserModule::OnRenderTreeProduced()");
DCHECK_EQ(MessageLoop::current(), self_message_loop_);
- if (splash_screen_ && !navigation_produced_main_render_tree_) {
+ if (main_web_module_generation != main_web_module_generation_) {
+ // Ignore render trees produced by old stale web modules. This might happen
+ // during a navigation transition.
+ return;
+ }
+
+ if (splash_screen_ && !splash_screen_->ShutdownSignaled()) {
splash_screen_->Shutdown();
}
if (application_state_ == base::kApplicationStatePreloading ||
@@ -579,18 +597,26 @@
return;
}
- navigation_produced_main_render_tree_ = true;
-
renderer::Submission renderer_submission(layout_results.render_tree,
layout_results.layout_time);
+ // Set the timeline id for the main web module. The main web module is
+ // assumed to be an interactive experience for which the default timeline
+ // configuration is already designed for, so we don't configure anything
+ // explicitly.
+ renderer_submission.timeline_info.id = current_main_web_module_timeline_id_;
+
renderer_submission.on_rasterized_callback = base::Bind(
&BrowserModule::OnRendererSubmissionRasterized, base::Unretained(this));
- main_web_module_layer_->Submit(renderer_submission, true /* receive_time */);
+ if (!splash_screen_) {
+ render_tree_combiner_->SetTimelineLayer(main_web_module_layer_.get());
+ }
+ main_web_module_layer_->Submit(renderer_submission);
#if defined(ENABLE_SCREENSHOT)
screen_shot_writer_->SetLastPipelineSubmission(renderer::Submission(
layout_results.render_tree, layout_results.layout_time));
#endif
+ SubmitCurrentRenderTreeToRenderer();
}
void BrowserModule::OnSplashScreenRenderTreeProduced(
@@ -606,20 +632,42 @@
renderer::Submission renderer_submission(layout_results.render_tree,
layout_results.layout_time);
+ // We customize some of the renderer pipeline timeline behavior to cater for
+ // non-interactive splash screen playback.
+ renderer_submission.timeline_info.id = current_splash_screen_timeline_id_;
+ // Since the splash screen is non-interactive, latency is not a concern.
+ // Latency reduction implies a speedup in animation playback speed which can
+ // make the splash screen play out quicker than intended.
+ renderer_submission.timeline_info.allow_latency_reduction = false;
+ // Increase the submission queue size to a larger value than usual. This
+ // is done because a) since we do not attempt to reduce latency, the queue
+ // tends to fill up more and b) the pipeline may end up receiving a number
+ // of render tree submissions caused by updated main web module render trees,
+ // which can fill the submission queue. Blowing the submission queue is
+ // particularly bad for the splash screen as it results in dropping of older
+ // submissions, which results in skipping forward during animations, which
+ // sucks.
+ renderer_submission.timeline_info.max_submission_queue_size =
+ std::max(8, renderer_submission.timeline_info.max_submission_queue_size);
+
renderer_submission.on_rasterized_callback = base::Bind(
&BrowserModule::OnRendererSubmissionRasterized, base::Unretained(this));
- splash_screen_layer_->Submit(renderer_submission, false /* receive_time */);
+ render_tree_combiner_->SetTimelineLayer(splash_screen_layer_.get());
+ splash_screen_layer_->Submit(renderer_submission);
#if defined(ENABLE_SCREENSHOT)
-// TODO: write screen shot using render_tree_combinder_ (to combine
+// TODO: write screen shot using render_tree_combiner_ (to combine
// splash screen and main web_module). Consider when the splash
// screen is overlaid on top of the main web module render tree, and
// a screenshot is taken : there will be a race condition on which
// web module update their render tree last.
#endif
+
+ SubmitCurrentRenderTreeToRenderer();
}
-void BrowserModule::OnWindowClose() {
+void BrowserModule::OnWindowClose(base::TimeDelta close_time) {
+ UNREFERENCED_PARAMETER(close_time);
#if defined(ENABLE_DEBUG_CONSOLE)
if (input_device_manager_fuzzer_) {
return;
@@ -712,6 +760,8 @@
debug_console_layer_->Submit(renderer::Submission(
layout_results.render_tree, layout_results.layout_time));
+
+ SubmitCurrentRenderTreeToRenderer();
}
#endif // defined(ENABLE_DEBUG_CONSOLE)
@@ -905,17 +955,26 @@
return false;
}
-void BrowserModule::DestroySplashScreen() {
+void BrowserModule::DestroySplashScreen(base::TimeDelta close_time) {
TRACE_EVENT0("cobalt::browser", "BrowserModule::DestroySplashScreen()");
if (MessageLoop::current() != self_message_loop_) {
self_message_loop_->PostTask(
- FROM_HERE, base::Bind(&BrowserModule::DestroySplashScreen, weak_this_));
+ FROM_HERE, base::Bind(&BrowserModule::DestroySplashScreen, weak_this_,
+ close_time));
return;
}
if (splash_screen_) {
lifecycle_observers_.RemoveObserver(splash_screen_.get());
}
- splash_screen_layer_.reset(NULL);
+ if (splash_screen_layer_) {
+ if (!close_time.is_zero()) {
+ // Ensure that the renderer renders each frame up until the window.close()
+ // is called on the splash screen's timeline, in order to ensure that the
+ // splash screen shutdown transition plays out completely.
+ renderer_module_->pipeline()->TimeFence(close_time);
+ }
+ splash_screen_layer_.reset(NULL);
+ }
splash_screen_.reset(NULL);
}
@@ -1146,8 +1205,7 @@
RendererModuleWithCameraOptions(options_.renderer_module_options,
input_device_manager_->camera_3d())));
- render_tree_combiner_.reset(
- new RenderTreeCombiner(renderer_module_.get(), GetViewportSize()));
+ render_tree_combiner_.reset(new RenderTreeCombiner());
// Create the main web module layer.
main_web_module_layer_ =
render_tree_combiner_->CreateLayer(kMainWebModuleZIndex);
@@ -1322,7 +1380,7 @@
static_cast<int>(auto_mem_->image_cache_size_in_bytes()->value());
options_.web_module_options.remote_typeface_cache_capacity = static_cast<int>(
auto_mem_->remote_typeface_cache_size_in_bytes()->value());
- options_.web_module_options.javascript_options.gc_threshold_bytes =
+ options_.web_module_options.javascript_engine_options.gc_threshold_bytes =
static_cast<size_t>(
auto_mem_->javascript_gc_threshold_in_bytes()->value());
if (web_module_) {
@@ -1357,5 +1415,13 @@
}
}
+void BrowserModule::SubmitCurrentRenderTreeToRenderer() {
+ base::optional<renderer::Submission> submission =
+ render_tree_combiner_->GetCurrentSubmission();
+ if (submission) {
+ renderer_module_->pipeline()->Submit(*submission);
+ }
+}
+
} // namespace browser
} // namespace cobalt
diff --git a/src/cobalt/browser/browser_module.h b/src/cobalt/browser/browser_module.h
index 7389e9c..32ec219 100644
--- a/src/cobalt/browser/browser_module.h
+++ b/src/cobalt/browser/browser_module.h
@@ -179,8 +179,10 @@
// Glue function to deal with the production of the main render tree,
// and will manage handing it off to the renderer.
void QueueOnRenderTreeProduced(
+ int web_module_generation,
const browser::WebModule::LayoutResults& layout_results);
void OnRenderTreeProduced(
+ int web_module_generation,
const browser::WebModule::LayoutResults& layout_results);
// Glue function to deal with the production of the splash screen render tree,
@@ -240,10 +242,10 @@
bool TryURLHandlers(const GURL& url);
// Destroys the splash screen, if currently displayed.
- void DestroySplashScreen();
+ void DestroySplashScreen(base::TimeDelta close_time);
// Called when web module has received window.close().
- void OnWindowClose();
+ void OnWindowClose(base::TimeDelta close_time);
// Called when web module has received window.minimize().
void OnWindowMinimize();
@@ -315,6 +317,11 @@
// Applies the current AutoMem settings to all applicable submodules.
void ApplyAutoMemSettings();
+ // If it exists, takes the current combined render tree from
+ // |render_tree_combiner_| and submits it to the pipeline in the renderer
+ // module.
+ void SubmitCurrentRenderTreeToRenderer();
+
// TODO:
// WeakPtr usage here can be avoided if BrowserModule has a thread to
// own where it can ensure that its tasks are all resolved when it is
@@ -509,9 +516,20 @@
// The splash screen cache.
scoped_ptr<SplashScreenCache> splash_screen_cache_;
- // Whether or not the main WebModule has produced any render trees yet for the
- // current navigation.
- bool navigation_produced_main_render_tree_;
+ // Number of main web modules that have take place so far, helpful for
+ // ditinguishing lingering events produced by older web modules as we switch
+ // from one to another. This is incremented with each navigation.
+ int main_web_module_generation_;
+
+ // Keeps track of a unique next ID to be assigned to new splash screen or
+ // main web module timelines.
+ int next_timeline_id_;
+
+ // The following values are specified on submissions sent into the renderer
+ // so that the renderer can identify when it is changing from one timeline
+ // to another (in which case it may need to clear its submission queue).
+ int current_splash_screen_timeline_id_;
+ int current_main_web_module_timeline_id_;
};
} // namespace browser
diff --git a/src/cobalt/browser/debug_console.cc b/src/cobalt/browser/debug_console.cc
index 79a6cd5..ec0aba7 100644
--- a/src/cobalt/browser/debug_console.cc
+++ b/src/cobalt/browser/debug_console.cc
@@ -167,11 +167,11 @@
network::NetworkModule* network_module, const math::Size& window_dimensions,
render_tree::ResourceProvider* resource_provider, float layout_refresh_rate,
const debug::Debugger::GetDebugServerCallback& get_debug_server_callback,
- const script::JavaScriptEngine::Options& js_options) {
+ const script::JavaScriptEngine::Options& javascript_engine_options) {
mode_ = GetInitialMode();
WebModule::Options web_module_options;
- web_module_options.javascript_options = js_options;
+ web_module_options.javascript_engine_options = javascript_engine_options;
web_module_options.name = "DebugConsoleWebModule";
// The debug console does not load any image assets.
web_module_options.image_cache_capacity = 0;
@@ -192,8 +192,8 @@
new WebModule(GURL(kInitialDebugConsoleUrl), initial_application_state,
render_tree_produced_callback,
base::Bind(&DebugConsole::OnError, base::Unretained(this)),
- base::Closure(), /* window_close_callback */
- base::Closure(), /* window_minimize_callback */
+ WebModule::CloseCallback(), /* window_close_callback */
+ base::Closure(), /* window_minimize_callback */
&stub_media_module_, network_module, window_dimensions,
1.f /*video_pixel_ratio*/, resource_provider,
layout_refresh_rate, web_module_options));
diff --git a/src/cobalt/browser/debug_console.h b/src/cobalt/browser/debug_console.h
index 6ed291d..3889f9a 100644
--- a/src/cobalt/browser/debug_console.h
+++ b/src/cobalt/browser/debug_console.h
@@ -45,7 +45,7 @@
render_tree::ResourceProvider* resource_provider,
float layout_refresh_rate,
const debug::Debugger::GetDebugServerCallback& get_debug_server_callback,
- const script::JavaScriptEngine::Options& js_options);
+ const script::JavaScriptEngine::Options& javascript_engine_options);
~DebugConsole();
// Filters a key event.
diff --git a/src/cobalt/browser/debug_console/console_values.js b/src/cobalt/browser/debug_console/console_values.js
index 516c249..7dac9df 100644
--- a/src/cobalt/browser/debug_console/console_values.js
+++ b/src/cobalt/browser/debug_console/console_values.js
@@ -22,7 +22,7 @@
this.DEFAULT_ACTIVE_SET =
'Cobalt DevTools WebDriver ' +
'Memory.CPU Memory.MainWebModule Memory.JS Memory.Font ' +
- 'Count.MainWebModule.ImageCache.RequestedResources ' +
+ 'Count.MainWebModule.ImageCache.Resource ' +
'Count.MainWebModule.DOM.HtmlElement Count.MainWebModule.Layout.Box ' +
'Event.Count.MainWebModule.KeyDown.DOM.HtmlElement.Added ' +
'Event.Count.MainWebModule.KeyDown.Layout.Box.Created ' +
diff --git a/src/cobalt/browser/lib/cobalt.def b/src/cobalt/browser/lib/cobalt.def
index 6fb1539..7a73eb4 100644
--- a/src/cobalt/browser/lib/cobalt.def
+++ b/src/cobalt/browser/lib/cobalt.def
@@ -18,6 +18,7 @@
CbLibGraphicsSetBeginRenderFrameCallback
CbLibGraphicsSetEndRenderFrameCallback
CbLibGrapicsGetMainTextureHandle
+ CbLibGraphicsSetTargetMainTextureSize
; From cobalt/render/rasterizer/lib/exported/video.h:
CbLibVideoSetOnUpdateProjectionType
diff --git a/src/cobalt/browser/render_tree_combiner.cc b/src/cobalt/browser/render_tree_combiner.cc
index 74727ec..87d4d1f 100644
--- a/src/cobalt/browser/render_tree_combiner.cc
+++ b/src/cobalt/browser/render_tree_combiner.cc
@@ -21,7 +21,6 @@
#include "base/time.h"
#include "cobalt/render_tree/composition_node.h"
#include "cobalt/render_tree/rect_node.h"
-#include "cobalt/renderer/renderer_module.h"
#include "cobalt/renderer/submission.h"
namespace cobalt {
@@ -35,25 +34,24 @@
RenderTreeCombiner::Layer::~Layer() {
DCHECK(render_tree_combiner_);
render_tree_combiner_->RemoveLayer(this);
- render_tree_combiner_->SubmitToRenderer();
}
void RenderTreeCombiner::Layer::Submit(
- const base::optional<renderer::Submission>& render_tree_submission,
- bool receive_time) {
+ const base::optional<renderer::Submission>& render_tree_submission) {
render_tree_ = render_tree_submission;
- if (receive_time) {
- receipt_time_ = base::TimeTicks::HighResNow();
- } else {
- receipt_time_ = base::nullopt;
- }
- DCHECK(render_tree_combiner_);
- render_tree_combiner_->SubmitToRenderer();
+ receipt_time_ = base::TimeTicks::HighResNow();
}
-RenderTreeCombiner::RenderTreeCombiner(
- renderer::RendererModule* renderer_module, const math::Size& viewport_size)
- : renderer_module_(renderer_module), viewport_size_(viewport_size) {}
+base::optional<base::TimeDelta> RenderTreeCombiner::Layer::CurrentTimeOffset() {
+ if (!receipt_time_) {
+ return base::nullopt;
+ } else {
+ return render_tree_->time_offset +
+ (base::TimeTicks::HighResNow() - *receipt_time_);
+ }
+}
+
+RenderTreeCombiner::RenderTreeCombiner() : timeline_layer_(NULL) {}
scoped_ptr<RenderTreeCombiner::Layer> RenderTreeCombiner::CreateLayer(
int z_index) {
@@ -66,7 +64,19 @@
return scoped_ptr<RenderTreeCombiner::Layer>(layers_[z_index]);
}
+void RenderTreeCombiner::SetTimelineLayer(Layer* layer) {
+ if (layer != NULL) {
+ DCHECK(OwnsLayer(layer));
+ }
+
+ timeline_layer_ = layer;
+}
+
void RenderTreeCombiner::RemoveLayer(const Layer* layer) {
+ if (timeline_layer_ == layer) {
+ SetTimelineLayer(NULL);
+ }
+
for (auto it = layers_.begin(); it != layers_.end(); /* no increment */) {
if (it->second == layer) {
it = layers_.erase(it);
@@ -76,36 +86,41 @@
}
}
-void RenderTreeCombiner::SubmitToRenderer() {
+base::optional<renderer::Submission>
+RenderTreeCombiner::GetCurrentSubmission() {
render_tree::CompositionNode::Builder builder;
// Add children for all layers in order.
- base::optional<renderer::Submission> first_tree = base::nullopt;
- base::optional<renderer::Submission> combined_submission = base::nullopt;
+ Layer* first_layer_with_render_tree = NULL;
for (auto it = layers_.begin(); it != layers_.end(); ++it) {
RenderTreeCombiner::Layer* layer = it->second;
if (layer->render_tree_) {
builder.AddChild(layer->render_tree_->render_tree);
- first_tree = layer->render_tree_;
- // Make the combined submission with the first receipt_time_ we find.
- if (!combined_submission && layer->receipt_time_) {
- combined_submission = renderer::Submission(*layer->render_tree_);
- combined_submission->time_offset =
- layer->render_tree_->time_offset +
- (base::TimeTicks::HighResNow() - *layer->receipt_time_);
- }
+ first_layer_with_render_tree = layer;
}
}
- if (!first_tree) {
- return;
- }
- if (!combined_submission) {
- // None of the layers store the time.
- combined_submission = renderer::Submission(*first_tree);
+ if (!first_layer_with_render_tree) {
+ return base::nullopt;
}
- combined_submission->render_tree = new render_tree::CompositionNode(builder);
- renderer_module_->pipeline()->Submit(*combined_submission);
+ Layer* timeline_layer = (timeline_layer_ && timeline_layer_->render_tree_)
+ ? timeline_layer_
+ : first_layer_with_render_tree;
+
+ renderer::Submission submission(new render_tree::CompositionNode(builder),
+ *timeline_layer->CurrentTimeOffset());
+ submission.timeline_info = timeline_layer->render_tree_->timeline_info;
+ return submission;
}
+
+bool RenderTreeCombiner::OwnsLayer(Layer* layer) {
+ for (const auto& iter_layer : layers_) {
+ if (iter_layer.second == layer) {
+ return true;
+ }
+ }
+ return false;
+}
+
} // namespace browser
} // namespace cobalt
diff --git a/src/cobalt/browser/render_tree_combiner.h b/src/cobalt/browser/render_tree_combiner.h
index 65f3127..a9bde63 100644
--- a/src/cobalt/browser/render_tree_combiner.h
+++ b/src/cobalt/browser/render_tree_combiner.h
@@ -20,7 +20,6 @@
#include "base/memory/scoped_ptr.h"
#include "base/optional.h"
#include "base/time.h"
-#include "cobalt/renderer/renderer_module.h"
#include "cobalt/renderer/submission.h"
namespace cobalt {
@@ -50,44 +49,55 @@
// Submit render tree to the layer, and specify whether the time
// received should be stored.
void Submit(
- const base::optional<renderer::Submission>& render_tree_submission,
- bool receive_time = false);
+ const base::optional<renderer::Submission>& render_tree_submission);
private:
friend class RenderTreeCombiner;
explicit Layer(RenderTreeCombiner* render_tree_combiner = NULL);
+ // Returns the current submission time for this particular layer. This is
+ // called by the RenderTreeCombiner on the |timeline_layer_| to determine
+ // which value to pass in as the submission time for the renderer.
+ base::optional<base::TimeDelta> CurrentTimeOffset();
+
RenderTreeCombiner* render_tree_combiner_;
base::optional<renderer::Submission> render_tree_;
base::optional<base::TimeTicks> receipt_time_;
};
- explicit RenderTreeCombiner(renderer::RendererModule* renderer_module,
- const math::Size& viewport_size);
+ RenderTreeCombiner();
~RenderTreeCombiner() {}
// Create a Layer with a given |z_index|. If a Layer already exists
// at |z_index|, return NULL, and no Layer is created.
scoped_ptr<Layer> CreateLayer(int z_index);
+ // Returns a current submission object that can be passed into a renderer
+ // for rasterization. If no layers with render trees exist, this will return
+ // a base::nullopt.
+ base::optional<renderer::Submission> GetCurrentSubmission();
+
+ // Names a single layer as the one responsible for providing the timeline
+ // id and configuration to the output combined render tree. Only a single
+ // layer can be responsible for providing the timeline.
+ void SetTimelineLayer(Layer* layer);
+
private:
+ // Returns true if the specified layer exists in this render tree combiner's
+ // current list of layers (e.g. |layers_|).
+ bool OwnsLayer(Layer* layer);
+
// The layers keyed on their z_index.
std::map<int, Layer*> layers_;
// Removes a layer from |layers_|. Called by the Layer destructor.
void RemoveLayer(const Layer* layer);
- // Combines the cached render trees and renders the result.
- void SubmitToRenderer();
-
- // Local reference to the render pipeline, so we can submit the combined tree.
- // Reference counted pointer not necessary here.
- renderer::RendererModule* renderer_module_;
-
- // The size of the output viewport.
- math::Size viewport_size_;
+ // Which layer is currently controlling the receipt time submitted to the
+ // rasterizer.
+ RenderTreeCombiner::Layer* timeline_layer_;
};
} // namespace browser
diff --git a/src/cobalt/browser/splash_screen.cc b/src/cobalt/browser/splash_screen.cc
index e2fa6ba..811baa0 100644
--- a/src/cobalt/browser/splash_screen.cc
+++ b/src/cobalt/browser/splash_screen.cc
@@ -30,16 +30,17 @@
const int kSplashShutdownSeconds = 2;
-void PostCallbackToMessageLoop(const base::Closure& callback,
- MessageLoop* message_loop) {
+typedef base::Callback<void(base::TimeDelta)> Callback;
+void PostCallbackToMessageLoop(const Callback& callback,
+ MessageLoop* message_loop,
+ base::TimeDelta time) {
DCHECK(message_loop);
- message_loop->PostTask(FROM_HERE, callback);
+ message_loop->PostTask(FROM_HERE, base::Bind(callback, time));
}
// TODO: consolidate definitions of BindToLoop / BindToCurrentLoop
// from here and media in base.
-base::Closure BindToLoop(const base::Closure& callback,
- MessageLoop* message_loop) {
+Callback BindToLoop(const Callback& callback, MessageLoop* message_loop) {
return base::Bind(&PostCallbackToMessageLoop, callback, message_loop);
}
@@ -58,10 +59,12 @@
const base::optional<GURL>& fallback_splash_screen_url,
const GURL& initial_main_web_module_url,
SplashScreenCache* splash_screen_cache,
- const base::Callback<void()>& on_splash_screen_shutdown_complete)
+ const base::Callback<void(base::TimeDelta)>&
+ on_splash_screen_shutdown_complete)
: render_tree_produced_callback_(render_tree_produced_callback),
self_message_loop_(MessageLoop::current()),
- on_splash_screen_shutdown_complete_(on_splash_screen_shutdown_complete) {
+ on_splash_screen_shutdown_complete_(on_splash_screen_shutdown_complete),
+ shutdown_signaled_(false) {
WebModule::Options web_module_options;
web_module_options.name = "SplashScreenWebModule";
@@ -86,10 +89,11 @@
web_module_options.splash_screen_cache = splash_screen_cache;
}
- base::Callback<void()> on_window_close(
+ base::Callback<void(base::TimeDelta)> on_window_close(
BindToLoop(on_splash_screen_shutdown_complete, self_message_loop_));
- web_module_options.on_before_unload_fired_but_not_handled = on_window_close;
+ web_module_options.on_before_unload_fired_but_not_handled =
+ base::Bind(on_window_close, base::TimeDelta());
DCHECK(url_to_pass);
web_module_.reset(new WebModule(
@@ -113,12 +117,18 @@
void SplashScreen::Shutdown() {
DCHECK_EQ(MessageLoop::current(), self_message_loop_);
DCHECK(web_module_);
+ DCHECK(!ShutdownSignaled()) << "Shutdown() should be called at most once.";
+
if (!on_splash_screen_shutdown_complete_.callback().is_null()) {
MessageLoop::current()->PostDelayedTask(
- FROM_HERE, on_splash_screen_shutdown_complete_.callback(),
+ FROM_HERE,
+ base::Bind(on_splash_screen_shutdown_complete_.callback(),
+ base::TimeDelta()),
base::TimeDelta::FromSeconds(kSplashShutdownSeconds));
}
web_module_->InjectBeforeUnloadEvent();
+
+ shutdown_signaled_ = true;
}
} // namespace browser
diff --git a/src/cobalt/browser/splash_screen.h b/src/cobalt/browser/splash_screen.h
index 3f1b8c3..f9315d2 100644
--- a/src/cobalt/browser/splash_screen.h
+++ b/src/cobalt/browser/splash_screen.h
@@ -33,18 +33,18 @@
//
class SplashScreen : public LifecycleObserver {
public:
- SplashScreen(
- base::ApplicationState initial_application_state,
- const WebModule::OnRenderTreeProducedCallback&
- render_tree_produced_callback,
- network::NetworkModule* network_module,
- const math::Size& window_dimensions,
- render_tree::ResourceProvider* resource_provider,
- float layout_refresh_rate,
- const base::optional<GURL>& fallback_splash_screen_url,
- const GURL& initial_main_web_module_url,
- cobalt::browser::SplashScreenCache* splash_screen_cache,
- const base::Callback<void()>& on_splash_screen_shutdown_complete);
+ SplashScreen(base::ApplicationState initial_application_state,
+ const WebModule::OnRenderTreeProducedCallback&
+ render_tree_produced_callback,
+ network::NetworkModule* network_module,
+ const math::Size& window_dimensions,
+ render_tree::ResourceProvider* resource_provider,
+ float layout_refresh_rate,
+ const base::optional<GURL>& fallback_splash_screen_url,
+ const GURL& initial_main_web_module_url,
+ cobalt::browser::SplashScreenCache* splash_screen_cache,
+ const base::Callback<void(base::TimeDelta)>&
+ on_splash_screen_shutdown_complete);
~SplashScreen();
void SetSize(const math::Size& window_dimensions, float video_pixel_ratio) {
@@ -72,6 +72,9 @@
// no handlers, |on_splash_screen_shutdown_complete_| is run immediately.
void Shutdown();
+ // Returns whether Shutdown() has been called before or not.
+ bool ShutdownSignaled() const { return shutdown_signaled_; }
+
private:
// Run when window.close() is called by the WebModule.
void OnWindowClosed();
@@ -88,7 +91,11 @@
// This is called by Shutdown (via window.close) or after
// the time limit has been exceeded.
- base::CancelableClosure on_splash_screen_shutdown_complete_;
+ base::CancelableCallback<void(base::TimeDelta)>
+ on_splash_screen_shutdown_complete_;
+
+ // True if SplashScreen::Shutdown() has been called.
+ bool shutdown_signaled_;
};
} // namespace browser
diff --git a/src/cobalt/browser/switches.cc b/src/cobalt/browser/switches.cc
index 11e98c3..aa69973 100644
--- a/src/cobalt/browser/switches.cc
+++ b/src/cobalt/browser/switches.cc
@@ -19,18 +19,10 @@
namespace switches {
#if defined(ENABLE_DEBUG_COMMAND_LINE_SWITCHES)
-// Allow insecure HTTP network connections.
-const char kAllowHttp[] = "allow_http";
// Decode audio data using ShellRawAudioDecoderStub.
const char kAudioDecoderStub[] = "audio_decoder_stub";
-// Set the content security policy enforcement mode: disable | enable
-// disable: Allow all resource loads. Ignore CSP totally.
-// enable: default mode. Enforce CSP strictly. Require CSP headers or fail
-// the initial document load.
-const char kCspMode[] = "csp_mode";
-
// Switches different debug console modes: on | hud | off
const char kDebugConsoleMode[] = "debug_console";
@@ -66,6 +58,10 @@
// app run as if it has no local storage.
const char kNullSavegame[] = "null_savegame";
+// Several checks are not enabled by default in non-production(gold) build. Use
+// this flag to simulate production build behavior.
+const char kProd[] = "prod";
+
// Specifies a proxy to use for network connections.
const char kProxy[] = "proxy";
@@ -75,6 +71,14 @@
// Creates a remote debugging server and listens on the specified port.
const char kRemoteDebuggingPort[] = "remote_debugging_port";
+// Forbid Cobalt to start without receiving csp headers which is enabled by
+// default in production.
+const char kRequireCSP[] = "require_csp";
+
+// Ask Cobalt to only accept https url which is enabled by default in
+// production.
+const char kRequireHTTPSLocation[] = "require_https";
+
// If this flag is set, Cobalt will automatically shutdown after the specified
// number of seconds have passed.
const char kShutdownAfter[] = "shutdown_after";
@@ -130,7 +134,7 @@
const char kFPSOverlay[] = "fps_overlay";
// Disables the hard-coded navigation whitelist without disabling any other
-// security checks. This is enabled in Gold builds.
+// security checks. This is enabled in production(gold) builds.
const char kDisableNavigationWhitelist[] = "disable_navigation_whitelist";
// Determines the capacity of the image cache which manages image surfaces
diff --git a/src/cobalt/browser/switches.h b/src/cobalt/browser/switches.h
index 4dc02ef..a0bbfde 100644
--- a/src/cobalt/browser/switches.h
+++ b/src/cobalt/browser/switches.h
@@ -20,9 +20,7 @@
namespace switches {
#if defined(ENABLE_DEBUG_COMMAND_LINE_SWITCHES)
-extern const char kAllowHttp[];
extern const char kAudioDecoderStub[];
-extern const char kCspMode[];
extern const char kDebugConsoleMode[];
extern const char kDisableWebDriver[];
extern const char kDisableWebmVp9[];
@@ -73,6 +71,10 @@
extern const char kVideoPlaybackRateMultiplier[];
+extern const char kProd[];
+extern const char kRequireHTTPSLocation[];
+extern const char kRequireCSP[];
+
} // namespace switches
} // namespace browser
} // namespace cobalt
diff --git a/src/cobalt/browser/testdata/dual-playback-demo/bear.mp4 b/src/cobalt/browser/testdata/dual-playback-demo/bear.mp4
new file mode 100644
index 0000000..3763b59
--- /dev/null
+++ b/src/cobalt/browser/testdata/dual-playback-demo/bear.mp4
Binary files differ
diff --git a/src/cobalt/browser/testdata/dual-playback-demo/dual-playback-demo.html b/src/cobalt/browser/testdata/dual-playback-demo/dual-playback-demo.html
new file mode 100644
index 0000000..f22d953
--- /dev/null
+++ b/src/cobalt/browser/testdata/dual-playback-demo/dual-playback-demo.html
@@ -0,0 +1,52 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title>Dual Playback Demo</title>
+ <style>
+ body {
+ margin: 0;
+ }
+
+ #player-layer {
+ width: 100%;
+ height: 100%;
+ }
+
+ video {
+ width: 100%;
+ height: 100%;
+ }
+
+ #ui-layer {
+ position: absolute;
+ top: 15%;
+ height: 85%;
+ width: 100%;
+ background-color: rgba(33, 33, 33, .75);
+ padding: 24px;
+ }
+
+ .item {
+ width: 427px;
+ height: 240px;
+ display: inline-block;
+ margin: 24px;
+ vertical-align: middle;
+ }
+ </style>
+ </head>
+ <body>
+ <div id="player-layer">
+ <video class="primary" muted="" autoplay="1" src="bear.mp4" loop=""></video>
+ </div>
+ <div id="ui-layer">
+ <div class="item" style="background-color: #DB4437"></div>
+ <div class="item" style="background-color: #9E9E9E">
+ <video class="secondary" muted="" autoplay="1" src="bear.mp4" loop=""></video>
+ </div>
+ <div class="item" style="background-color: #4285F4"></div>
+ <div class="item" style="background-color: #0F9D58"></div>
+ <div class="item" style="background-color: #F4B400"></div>
+ </div>
+ </body>
+</html>
diff --git a/src/cobalt/browser/web_module.cc b/src/cobalt/browser/web_module.cc
index 150b2c8..2991246 100644
--- a/src/cobalt/browser/web_module.cc
+++ b/src/cobalt/browser/web_module.cc
@@ -424,7 +424,8 @@
dom_parser_.reset(new dom_parser::Parser(
kDOMMaxElementDepth,
- base::Bind(&WebModule::Impl::OnError, base::Unretained(this))));
+ base::Bind(&WebModule::Impl::OnError, base::Unretained(this)),
+ data.options.require_csp));
DCHECK(dom_parser_);
blob_registry_.reset(new dom::Blob::Registry);
@@ -487,8 +488,8 @@
new browser::WebModuleStatTracker(name_, data.options.track_event_stats));
DCHECK(web_module_stat_tracker_);
- javascript_engine_ =
- script::JavaScriptEngine::CreateEngine(data.options.javascript_options);
+ javascript_engine_ = script::JavaScriptEngine::CreateEngine(
+ data.options.javascript_engine_options);
DCHECK(javascript_engine_);
#if defined(COBALT_ENABLE_JAVASCRIPT_ERROR_LOGGING)
@@ -531,7 +532,8 @@
data.options.navigation_callback,
base::Bind(&WebModule::Impl::OnError, base::Unretained(this)),
data.network_module->cookie_jar(), data.network_module->GetPostSender(),
- data.options.location_policy, data.options.csp_enforcement_mode,
+ data.options.location_policy, data.options.require_csp,
+ data.options.csp_enforcement_mode,
base::Bind(&WebModule::Impl::OnCspPolicyChanged, base::Unretained(this)),
base::Bind(&WebModule::Impl::OnRanAnimationFrameCallbacks,
base::Unretained(this)),
@@ -1039,7 +1041,7 @@
const GURL& initial_url, base::ApplicationState initial_application_state,
const OnRenderTreeProducedCallback& render_tree_produced_callback,
const OnErrorCallback& error_callback,
- const base::Closure& window_close_callback,
+ const CloseCallback& window_close_callback,
const base::Closure& window_minimize_callback,
media::MediaModule* media_module, network::NetworkModule* network_module,
const math::Size& window_dimensions, float video_pixel_ratio,
diff --git a/src/cobalt/browser/web_module.h b/src/cobalt/browser/web_module.h
index ba23707..281664b 100644
--- a/src/cobalt/browser/web_module.h
+++ b/src/cobalt/browser/web_module.h
@@ -128,6 +128,9 @@
// can't be changed from the whitelisted origins.
std::string location_policy;
+ // Whether Cobalt is forbidden to render without receiving CSP headers.
+ csp::CSPHeaderPolicy require_csp;
+
// Image cache capacity in bytes.
int image_cache_capacity;
@@ -172,7 +175,7 @@
// To support 3D camera movements.
scoped_refptr<input::Camera3D> camera_3d;
- script::JavaScriptEngine::Options javascript_options;
+ script::JavaScriptEngine::Options javascript_engine_options;
// The video playback rate will be multiplied with the following value. Its
// default value is 1.0.
@@ -202,12 +205,13 @@
typedef base::Callback<void(const LayoutResults&)>
OnRenderTreeProducedCallback;
typedef base::Callback<void(const GURL&, const std::string&)> OnErrorCallback;
+ typedef dom::Window::CloseCallback CloseCallback;
WebModule(const GURL& initial_url,
base::ApplicationState initial_application_state,
const OnRenderTreeProducedCallback& render_tree_produced_callback,
const OnErrorCallback& error_callback,
- const base::Closure& window_close_callback,
+ const CloseCallback& window_close_callback,
const base::Closure& window_minimize_callback,
media::MediaModule* media_module,
network::NetworkModule* network_module,
@@ -288,7 +292,7 @@
base::ApplicationState initial_application_state,
const OnRenderTreeProducedCallback& render_tree_produced_callback,
const OnErrorCallback& error_callback,
- const base::Closure& window_close_callback,
+ const CloseCallback& window_close_callback,
const base::Closure& window_minimize_callback,
media::MediaModule* media_module,
network::NetworkModule* network_module,
@@ -315,7 +319,7 @@
base::ApplicationState initial_application_state;
OnRenderTreeProducedCallback render_tree_produced_callback;
OnErrorCallback error_callback;
- const base::Closure& window_close_callback;
+ const CloseCallback& window_close_callback;
const base::Closure& window_minimize_callback;
media::MediaModule* media_module;
network::NetworkModule* network_module;
diff --git a/src/cobalt/build/build.id b/src/cobalt/build/build.id
index c1d9146..f701966 100644
--- a/src/cobalt/build/build.id
+++ b/src/cobalt/build/build.id
@@ -1 +1 @@
-98776
\ No newline at end of file
+101483
\ No newline at end of file
diff --git a/src/cobalt/csp/content_security_policy.h b/src/cobalt/csp/content_security_policy.h
index 5725ffb..95789a1 100644
--- a/src/cobalt/csp/content_security_policy.h
+++ b/src/cobalt/csp/content_security_policy.h
@@ -42,6 +42,12 @@
std::string header;
};
+// Whether Cobalt can start without CSP headers.
+enum CSPHeaderPolicy {
+ kCSPRequired,
+ kCSPOptional,
+};
+
// A callback that a URL fetcher will call to check if the URL is permitted
// by our security policy. This may be called multiple times if the URL results
// in a redirect. The callback should return |true| if the URL is safe to
diff --git a/src/cobalt/csp/directive_list.cc b/src/cobalt/csp/directive_list.cc
index f0fb591..7ce85e0 100644
--- a/src/cobalt/csp/directive_list.cc
+++ b/src/cobalt/csp/directive_list.cc
@@ -38,7 +38,7 @@
std::string encoded;
bool ok = base::Base64Encode(digest_piece, &encoded);
if (ok) {
- return "sha256-" + encoded;
+ return "'sha256-" + encoded + "'";
} else {
DLOG(WARNING) << "Base64Encode failed on " << content;
return "sha256-...";
@@ -221,10 +221,22 @@
suffix =
" Note that 'unsafe-inline' is ignored if either a hash or nonce value "
"is present in the source list.";
+ } else if (directive->hash_or_nonce_present()) {
+ suffix =
+ " Either the 'unsafe-inline' keyword, a hash (" + hash_value +
+ "), or a nonce ('nonce-...') is required to enable inline execution.";
+ DigestValue digest_value;
+ HashAlgorithm hash_algorithm;
+ SourceList::ParseHash(hash_value.c_str(),
+ hash_value.c_str() + hash_value.length(),
+ &digest_value, &hash_algorithm);
+ if (directive->AllowHash(HashValue(hash_algorithm, digest_value))) {
+ return true;
+ }
} else {
suffix =
- " Either the 'unsafe-inline' keyword, a hash ('" + hash_value +
- "'), or a nonce ('nonce-...') is required to enable inline execution.";
+ " Either the 'unsafe-inline' keyword, a hash (" + hash_value +
+ "), or a nonce ('nonce-...') is required to enable inline execution.";
if (directive == default_src_)
suffix = suffix + " Note also that '" +
std::string(is_script ? "script" : "style") +
diff --git a/src/cobalt/csp/source_list.cc b/src/cobalt/csp/source_list.cc
index 1f6fcd1..bc4615d 100644
--- a/src/cobalt/csp/source_list.cc
+++ b/src/cobalt/csp/source_list.cc
@@ -404,6 +404,7 @@
// hash-algorithm = "sha1" / "sha256" / "sha384" / "sha512"
// hash-value = 1*( ALPHA / DIGIT / "+" / "/" / "=" )
//
+// static
bool SourceList::ParseHash(const char* begin, const char* end,
DigestValue* hash, HashAlgorithm* hash_algorithm) {
std::string prefix;
diff --git a/src/cobalt/csp/source_list.h b/src/cobalt/csp/source_list.h
index f3b3d9c..921ac47 100644
--- a/src/cobalt/csp/source_list.h
+++ b/src/cobalt/csp/source_list.h
@@ -56,6 +56,9 @@
uint8 hash_algorithms_used() const { return hash_algorithms_used_; }
bool hash_or_nonce_present() const;
+ static bool ParseHash(const char* begin, const char* end, DigestValue* hash,
+ HashAlgorithm* hash_algorithm);
+
private:
bool ParseSource(const char* begin, const char* end,
SourceConfig* source_config);
@@ -66,8 +69,6 @@
SourceConfig::WildcardDisposition* port_disposition);
bool ParsePath(const char* begin, const char* end, std::string* path);
bool ParseNonce(const char* begin, const char* end, std::string* nonce);
- bool ParseHash(const char* begin, const char* end, DigestValue* hash,
- HashAlgorithm* hash_algorithm);
void AddSourceLocalhost();
void AddSourceLocalNetwork();
diff --git a/src/cobalt/csp/source_list_test.cc b/src/cobalt/csp/source_list_test.cc
index febdbce..3f298d8 100644
--- a/src/cobalt/csp/source_list_test.cc
+++ b/src/cobalt/csp/source_list_test.cc
@@ -525,5 +525,34 @@
}
#endif
+TEST_F(SourceListTest, TestInvalidHash) {
+ std::string sources = "'sha256-c3uoUQo23pT8hqB5MoAZnI9LiPUc+lWgGBKHfV07iAM='";
+ SourceList source_list(&checker_, csp_.get(), "style-src");
+ ParseSourceList(&source_list, sources);
+
+ std::string hash_value =
+ "'sha256-IegLaWGTFJzK5gbj1YVsl+RfqHIqXhXan88eiG9GQwE='";
+ DigestValue digest_value;
+ HashAlgorithm hash_algorithm;
+ EXPECT_TRUE(SourceList::ParseHash(hash_value.c_str(),
+ hash_value.c_str() + hash_value.length(),
+ &digest_value, &hash_algorithm));
+ EXPECT_FALSE(source_list.AllowHash(HashValue(hash_algorithm, digest_value)));
+}
+
+TEST_F(SourceListTest, TestValidHash) {
+ std::string sources = "'sha256-IegLaWGTFJzK5gbj1YVsl+RfqHIqXhXan88eiG9GQwE='";
+ SourceList source_list(&checker_, csp_.get(), "style-src");
+ ParseSourceList(&source_list, sources);
+
+ std::string hash_value = sources;
+ DigestValue digest_value;
+ HashAlgorithm hash_algorithm;
+ EXPECT_TRUE(SourceList::ParseHash(hash_value.c_str(),
+ hash_value.c_str() + hash_value.length(),
+ &digest_value, &hash_algorithm));
+ EXPECT_TRUE(source_list.AllowHash(HashValue(hash_algorithm, digest_value)));
+}
+
} // namespace csp
} // namespace cobalt
diff --git a/src/cobalt/csp/testdata/invalid_hash.html b/src/cobalt/csp/testdata/invalid_hash.html
new file mode 100644
index 0000000..76991b4
--- /dev/null
+++ b/src/cobalt/csp/testdata/invalid_hash.html
@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<!--
+ Copyright 2017 Google Inc. All Rights Reserved.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<html>
+
+<head>
+ <meta http-equiv="Content-Security-Policy" content="default-src 'none'; style-src 'sha256-c3uoUQo23pT8hqB5MoAZnI9LiPUc+lWgGBKHfV07iAM=';">
+</head>
+
+<style>
+ body {
+ background-color: #00ff00;
+ }
+</style>
+<body></body>
+</html>
diff --git a/src/cobalt/csp/testdata/valid_hash.html b/src/cobalt/csp/testdata/valid_hash.html
new file mode 100644
index 0000000..8b4a9ba
--- /dev/null
+++ b/src/cobalt/csp/testdata/valid_hash.html
@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<!--
+ Copyright 2017 Google Inc. All Rights Reserved.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<html>
+
+<head>
+ <meta http-equiv="Content-Security-Policy" content="default-src 'none'; style-src 'sha256-IegLaWGTFJzK5gbj1YVsl+RfqHIqXhXan88eiG9GQwE=';">
+</head>
+
+<style>
+ body {
+ background-color: #00ff00;
+ }
+</style>
+<body></body>
+</html>
diff --git a/src/cobalt/css_parser/grammar.y b/src/cobalt/css_parser/grammar.y
index 36e8e8a..47f3bc5 100644
--- a/src/cobalt/css_parser/grammar.y
+++ b/src/cobalt/css_parser/grammar.y
@@ -87,6 +87,8 @@
%token kBackgroundSizeToken // background-size
%token kBackgroundToken // background
%token kBorderToken // border
+%token kBorderBottomLeftRadiusToken // border-bottom-left-radius
+%token kBorderBottomRightRadiusToken // border-bottom-right-radius
%token kBorderBottomToken // border-bottom
%token kBorderBottomColorToken // border-bottom-color
%token kBorderBottomStyleToken // border-bottom-style
@@ -104,6 +106,8 @@
%token kBorderStyleToken // border-style
%token kBorderTopToken // border-top
%token kBorderTopColorToken // border-top-color
+%token kBorderTopLeftRadiusToken // border-top-left-radius
+%token kBorderTopRightRadiusToken // border-top-right-radius
%token kBorderTopStyleToken // border-top-style
%token kBorderTopWidthToken // border-top-width
%token kBorderWidthToken // border-width
@@ -523,6 +527,8 @@
background_size_property_value
background_size_property_value_without_common_values
border_color_property_value
+ border_radius_element
+ border_radius_element_with_common_values
border_radius_property_value
border_style_property_value
border_width_element
@@ -757,6 +763,7 @@
%union { cssom::PropertyListValue::Builder* property_list; }
%type <property_list> background_size_property_list
border_color_property_list
+ border_radius_property_list
border_style_property_list
border_width_property_list
comma_separated_animation_direction_list
@@ -1325,6 +1332,14 @@
$$ = TrivialStringPiece::FromCString(
cssom::GetPropertyName(cssom::kBorderProperty));
}
+ | kBorderBottomLeftRadiusToken {
+ $$ = TrivialStringPiece::FromCString(
+ cssom::GetPropertyName(cssom::kBorderBottomLeftRadiusProperty));
+ }
+ | kBorderBottomRightRadiusToken {
+ $$ = TrivialStringPiece::FromCString(
+ cssom::GetPropertyName(cssom::kBorderBottomRightRadiusProperty));
+ }
| kBorderBottomToken {
$$ = TrivialStringPiece::FromCString(
cssom::GetPropertyName(cssom::kBorderBottomProperty));
@@ -1393,6 +1408,14 @@
$$ = TrivialStringPiece::FromCString(
cssom::GetPropertyName(cssom::kBorderTopColorProperty));
}
+ | kBorderTopLeftRadiusToken {
+ $$ = TrivialStringPiece::FromCString(
+ cssom::GetPropertyName(cssom::kBorderTopLeftRadiusProperty));
+ }
+ | kBorderTopRightRadiusToken {
+ $$ = TrivialStringPiece::FromCString(
+ cssom::GetPropertyName(cssom::kBorderTopRightRadiusProperty));
+ }
| kBorderTopStyleToken {
$$ = TrivialStringPiece::FromCString(
cssom::GetPropertyName(cssom::kBorderTopStyleProperty));
@@ -3461,11 +3484,44 @@
// The radii of a quarter ellipse that defines the shape of the corner
// of the outer border edge.
// https://www.w3.org/TR/css3-background/#the-border-radius
-border_radius_property_value:
+border_radius_element:
positive_length_percent_property_value { $$ = $1; }
+ ;
+border_radius_element_with_common_values:
+ border_radius_element
| common_values
;
+border_radius_property_list:
+ /* empty */ {
+ $$ = new cssom::PropertyListValue::Builder();
+ }
+ | border_radius_property_list border_radius_element {
+ scoped_ptr<cssom::PropertyListValue::Builder> property_value($1);
+ property_value->push_back(MakeScopedRefPtrAndRelease($2));
+ $$ = property_value.release();
+ }
+ ;
+
+border_radius_property_value:
+ border_radius_property_list {
+ scoped_ptr<cssom::PropertyListValue::Builder> property_value($1);
+ if (property_value->size() > 0u &&
+ property_value->size() <= 4u) {
+ $$ = AddRef(new cssom::PropertyListValue(property_value.Pass()));
+ } else {
+ parser_impl->LogWarning(@1, "invalid number of border radius values");
+ $$ = NULL;
+ }
+ }
+ | common_values {
+ scoped_ptr<cssom::PropertyListValue::Builder> property_value(
+ new cssom::PropertyListValue::Builder());
+ property_value->push_back($1);
+ $$ = AddRef(new cssom::PropertyListValue(property_value.Pass()));
+ }
+ ;
+
box_shadow_property_element:
length {
if ($<shadow_info>0->length_vector.size() == 2) {
@@ -5610,6 +5666,18 @@
$$ = NULL;
}
}
+ | kBorderBottomLeftRadiusToken maybe_whitespace colon border_radius_element_with_common_values
+ maybe_important {
+ $$ = $4 ? new PropertyDeclaration(cssom::kBorderBottomLeftRadiusProperty,
+ MakeScopedRefPtrAndRelease($4), $5)
+ : NULL;
+ }
+ | kBorderBottomRightRadiusToken maybe_whitespace colon border_radius_element_with_common_values
+ maybe_important {
+ $$ = $4 ? new PropertyDeclaration(cssom::kBorderBottomRightRadiusProperty,
+ MakeScopedRefPtrAndRelease($4), $5)
+ : NULL;
+ }
| kBorderBottomToken maybe_whitespace colon border_or_outline_property_value
maybe_important {
scoped_ptr<BorderOrOutlineShorthand> border($4);
@@ -5733,9 +5801,38 @@
}
| kBorderRadiusToken maybe_whitespace colon border_radius_property_value
maybe_important {
- $$ = $4 ? new PropertyDeclaration(cssom::kBorderRadiusProperty,
- MakeScopedRefPtrAndRelease($4), $5)
- : NULL;
+ scoped_refptr<cssom::PropertyValue> property_list_value(
+ MakeScopedRefPtrAndRelease($4));
+ if (property_list_value) {
+ BorderShorthandToLonghand shorthand_to_longhand;
+ shorthand_to_longhand.Assign4BordersBasedOnPropertyList(
+ property_list_value);
+
+ scoped_ptr<PropertyDeclaration> property_declaration(
+ new PropertyDeclaration($5));
+
+ // Unpack border radius.
+ property_declaration->property_values.push_back(
+ PropertyDeclaration::PropertyKeyValuePair(
+ cssom::kBorderTopLeftRadiusProperty,
+ shorthand_to_longhand.border_top));
+ property_declaration->property_values.push_back(
+ PropertyDeclaration::PropertyKeyValuePair(
+ cssom::kBorderTopRightRadiusProperty,
+ shorthand_to_longhand.border_right));
+ property_declaration->property_values.push_back(
+ PropertyDeclaration::PropertyKeyValuePair(
+ cssom::kBorderBottomRightRadiusProperty,
+ shorthand_to_longhand.border_bottom));
+ property_declaration->property_values.push_back(
+ PropertyDeclaration::PropertyKeyValuePair(
+ cssom::kBorderBottomLeftRadiusProperty,
+ shorthand_to_longhand.border_left));
+
+ $$ = property_declaration.release();
+ } else {
+ $$ = NULL;
+ }
}
| kBorderRightToken maybe_whitespace colon border_or_outline_property_value
maybe_important {
@@ -5846,6 +5943,18 @@
MakeScopedRefPtrAndRelease($4), $5)
: NULL;
}
+ | kBorderTopLeftRadiusToken maybe_whitespace colon border_radius_element_with_common_values
+ maybe_important {
+ $$ = $4 ? new PropertyDeclaration(cssom::kBorderTopLeftRadiusProperty,
+ MakeScopedRefPtrAndRelease($4), $5)
+ : NULL;
+ }
+ | kBorderTopRightRadiusToken maybe_whitespace colon border_radius_element_with_common_values
+ maybe_important {
+ $$ = $4 ? new PropertyDeclaration(cssom::kBorderTopRightRadiusProperty,
+ MakeScopedRefPtrAndRelease($4), $5)
+ : NULL;
+ }
| kBorderTopStyleToken maybe_whitespace colon line_style_with_common_values
maybe_important {
$$ = $4 ? new PropertyDeclaration(cssom::kBorderTopStyleProperty,
diff --git a/src/cobalt/css_parser/parser_test.cc b/src/cobalt/css_parser/parser_test.cc
index 4a7a792..8af545c 100644
--- a/src/cobalt/css_parser/parser_test.cc
+++ b/src/cobalt/css_parser/parser_test.cc
@@ -3869,29 +3869,268 @@
EXPECT_FALSE(style->GetPropertyValue(cssom::kBorderLeftWidthProperty));
}
-TEST_F(ParserTest, ParsesBorderRadiusLength) {
+TEST_F(ParserTest, ParsesBorderRadiusSingleLength) {
scoped_refptr<cssom::CSSDeclaredStyleData> style =
parser_.ParseStyleDeclarationList("border-radius: 0.2em;",
source_location_);
- scoped_refptr<cssom::LengthValue> border_radius =
+ scoped_refptr<cssom::LengthValue> border_top_left_radius =
dynamic_cast<cssom::LengthValue*>(
- style->GetPropertyValue(cssom::kBorderRadiusProperty).get());
- ASSERT_TRUE(border_radius);
- EXPECT_FLOAT_EQ(0.2f, border_radius->value());
- EXPECT_EQ(cssom::kFontSizesAkaEmUnit, border_radius->unit());
+ style->GetPropertyValue(cssom::kBorderTopLeftRadiusProperty).get());
+ ASSERT_TRUE(border_top_left_radius);
+ EXPECT_FLOAT_EQ(0.2f, border_top_left_radius->value());
+ EXPECT_EQ(cssom::kFontSizesAkaEmUnit, border_top_left_radius->unit());
+
+ scoped_refptr<cssom::LengthValue> border_top_right_radius =
+ dynamic_cast<cssom::LengthValue*>(
+ style->GetPropertyValue(cssom::kBorderTopRightRadiusProperty).get());
+ ASSERT_TRUE(border_top_right_radius);
+ EXPECT_FLOAT_EQ(0.2f, border_top_right_radius->value());
+ EXPECT_EQ(cssom::kFontSizesAkaEmUnit, border_top_right_radius->unit());
+
+ scoped_refptr<cssom::LengthValue> border_bottom_right_radius =
+ dynamic_cast<cssom::LengthValue*>(
+ style->GetPropertyValue(cssom::kBorderBottomRightRadiusProperty)
+ .get());
+ ASSERT_TRUE(border_bottom_right_radius);
+ EXPECT_FLOAT_EQ(0.2f, border_bottom_right_radius->value());
+ EXPECT_EQ(cssom::kFontSizesAkaEmUnit, border_bottom_right_radius->unit());
+
+ scoped_refptr<cssom::LengthValue> border_bottom_left_radius =
+ dynamic_cast<cssom::LengthValue*>(
+ style->GetPropertyValue(cssom::kBorderBottomLeftRadiusProperty)
+ .get());
+ ASSERT_TRUE(border_bottom_left_radius);
+ EXPECT_FLOAT_EQ(0.2f, border_bottom_left_radius->value());
+ EXPECT_EQ(cssom::kFontSizesAkaEmUnit, border_bottom_left_radius->unit());
}
-TEST_F(ParserTest, ParsesBorderRadiusPercentage) {
+TEST_F(ParserTest, ParsesBorderRadiusSinglePercentage) {
scoped_refptr<cssom::CSSDeclaredStyleData> style =
parser_.ParseStyleDeclarationList("border-radius: 50%;",
source_location_);
- scoped_refptr<cssom::PercentageValue> border_radius =
+ scoped_refptr<cssom::PercentageValue> border_top_left_radius =
dynamic_cast<cssom::PercentageValue*>(
- style->GetPropertyValue(cssom::kBorderRadiusProperty).get());
- ASSERT_TRUE(border_radius);
- EXPECT_FLOAT_EQ(0.5f, border_radius->value());
+ style->GetPropertyValue(cssom::kBorderTopLeftRadiusProperty).get());
+ ASSERT_TRUE(border_top_left_radius);
+ EXPECT_FLOAT_EQ(0.5f, border_top_left_radius->value());
+
+ scoped_refptr<cssom::PercentageValue> border_top_right_radius =
+ dynamic_cast<cssom::PercentageValue*>(
+ style->GetPropertyValue(cssom::kBorderTopRightRadiusProperty).get());
+ ASSERT_TRUE(border_top_right_radius);
+ EXPECT_FLOAT_EQ(0.5f, border_top_right_radius->value());
+
+ scoped_refptr<cssom::PercentageValue> border_bottom_right_radius =
+ dynamic_cast<cssom::PercentageValue*>(
+ style->GetPropertyValue(cssom::kBorderBottomRightRadiusProperty)
+ .get());
+ ASSERT_TRUE(border_bottom_right_radius);
+ EXPECT_FLOAT_EQ(0.5f, border_bottom_right_radius->value());
+
+ scoped_refptr<cssom::PercentageValue> border_bottom_left_radius =
+ dynamic_cast<cssom::PercentageValue*>(
+ style->GetPropertyValue(cssom::kBorderBottomLeftRadiusProperty)
+ .get());
+ ASSERT_TRUE(border_bottom_left_radius);
+ EXPECT_FLOAT_EQ(0.5f, border_bottom_left_radius->value());
+}
+
+TEST_F(ParserTest, ParsesBorderRadiusWithTwoLengths) {
+ scoped_refptr<cssom::CSSDeclaredStyleData> style =
+ parser_.ParseStyleDeclarationList("border-radius: .8em 20px;",
+ source_location_);
+
+ scoped_refptr<cssom::LengthValue> border_top_left_radius =
+ dynamic_cast<cssom::LengthValue*>(
+ style->GetPropertyValue(cssom::kBorderTopLeftRadiusProperty).get());
+ ASSERT_TRUE(border_top_left_radius);
+ EXPECT_FLOAT_EQ(0.8f, border_top_left_radius->value());
+ EXPECT_EQ(cssom::kFontSizesAkaEmUnit, border_top_left_radius->unit());
+
+ scoped_refptr<cssom::LengthValue> border_top_right_radius =
+ dynamic_cast<cssom::LengthValue*>(
+ style->GetPropertyValue(cssom::kBorderTopRightRadiusProperty).get());
+ ASSERT_TRUE(border_top_right_radius);
+ EXPECT_FLOAT_EQ(20.0f, border_top_right_radius->value());
+ EXPECT_EQ(cssom::kPixelsUnit, border_top_right_radius->unit());
+
+ scoped_refptr<cssom::LengthValue> border_bottom_right_radius =
+ dynamic_cast<cssom::LengthValue*>(
+ style->GetPropertyValue(cssom::kBorderBottomRightRadiusProperty)
+ .get());
+ ASSERT_TRUE(border_bottom_right_radius);
+ EXPECT_FLOAT_EQ(0.8f, border_bottom_right_radius->value());
+ EXPECT_EQ(cssom::kFontSizesAkaEmUnit, border_bottom_right_radius->unit());
+
+ scoped_refptr<cssom::LengthValue> border_bottom_left_radius =
+ dynamic_cast<cssom::LengthValue*>(
+ style->GetPropertyValue(cssom::kBorderBottomLeftRadiusProperty)
+ .get());
+ ASSERT_TRUE(border_bottom_left_radius);
+ EXPECT_FLOAT_EQ(20.0f, border_bottom_left_radius->value());
+ EXPECT_EQ(cssom::kPixelsUnit, border_bottom_left_radius->unit());
+}
+
+TEST_F(ParserTest, ParsesBorderRadiusWithLengthAndPercentage) {
+ scoped_refptr<cssom::CSSDeclaredStyleData> style =
+ parser_.ParseStyleDeclarationList("border-radius: .8em 20%;",
+ source_location_);
+
+ scoped_refptr<cssom::LengthValue> border_top_left_radius =
+ dynamic_cast<cssom::LengthValue*>(
+ style->GetPropertyValue(cssom::kBorderTopLeftRadiusProperty).get());
+ ASSERT_TRUE(border_top_left_radius);
+ EXPECT_FLOAT_EQ(0.8f, border_top_left_radius->value());
+ EXPECT_EQ(cssom::kFontSizesAkaEmUnit, border_top_left_radius->unit());
+
+ scoped_refptr<cssom::PercentageValue> border_top_right_radius =
+ dynamic_cast<cssom::PercentageValue*>(
+ style->GetPropertyValue(cssom::kBorderTopRightRadiusProperty).get());
+ ASSERT_TRUE(border_top_right_radius);
+ EXPECT_FLOAT_EQ(0.2f, border_top_right_radius->value());
+
+ scoped_refptr<cssom::LengthValue> border_bottom_right_radius =
+ dynamic_cast<cssom::LengthValue*>(
+ style->GetPropertyValue(cssom::kBorderBottomRightRadiusProperty)
+ .get());
+ ASSERT_TRUE(border_bottom_right_radius);
+ EXPECT_FLOAT_EQ(0.8f, border_bottom_right_radius->value());
+ EXPECT_EQ(cssom::kFontSizesAkaEmUnit, border_bottom_right_radius->unit());
+
+ scoped_refptr<cssom::PercentageValue> border_bottom_left_radius =
+ dynamic_cast<cssom::PercentageValue*>(
+ style->GetPropertyValue(cssom::kBorderBottomLeftRadiusProperty)
+ .get());
+ ASSERT_TRUE(border_bottom_left_radius);
+ EXPECT_FLOAT_EQ(0.2f, border_bottom_left_radius->value());
+}
+
+TEST_F(ParserTest, ParsesBorderRadiusWithThreeLengths) {
+ scoped_refptr<cssom::CSSDeclaredStyleData> style =
+ parser_.ParseStyleDeclarationList("border-radius: .8em 20px 10px;",
+ source_location_);
+
+ scoped_refptr<cssom::LengthValue> border_top_left_radius =
+ dynamic_cast<cssom::LengthValue*>(
+ style->GetPropertyValue(cssom::kBorderTopLeftRadiusProperty).get());
+ ASSERT_TRUE(border_top_left_radius);
+ EXPECT_FLOAT_EQ(0.8f, border_top_left_radius->value());
+ EXPECT_EQ(cssom::kFontSizesAkaEmUnit, border_top_left_radius->unit());
+
+ scoped_refptr<cssom::LengthValue> border_top_right_radius =
+ dynamic_cast<cssom::LengthValue*>(
+ style->GetPropertyValue(cssom::kBorderTopRightRadiusProperty).get());
+ ASSERT_TRUE(border_top_right_radius);
+ EXPECT_FLOAT_EQ(20.0f, border_top_right_radius->value());
+ EXPECT_EQ(cssom::kPixelsUnit, border_top_right_radius->unit());
+
+ scoped_refptr<cssom::LengthValue> border_bottom_right_radius =
+ dynamic_cast<cssom::LengthValue*>(
+ style->GetPropertyValue(cssom::kBorderBottomRightRadiusProperty)
+ .get());
+ ASSERT_TRUE(border_bottom_right_radius);
+ EXPECT_FLOAT_EQ(10.0f, border_bottom_right_radius->value());
+ EXPECT_EQ(cssom::kPixelsUnit, border_bottom_right_radius->unit());
+
+ scoped_refptr<cssom::LengthValue> border_bottom_left_radius =
+ dynamic_cast<cssom::LengthValue*>(
+ style->GetPropertyValue(cssom::kBorderBottomLeftRadiusProperty)
+ .get());
+ ASSERT_TRUE(border_bottom_left_radius);
+ EXPECT_FLOAT_EQ(20.0f, border_bottom_left_radius->value());
+ EXPECT_EQ(cssom::kPixelsUnit, border_bottom_left_radius->unit());
+}
+
+TEST_F(ParserTest, ParsesBorderRadiusWithFourLengths) {
+ scoped_refptr<cssom::CSSDeclaredStyleData> style =
+ parser_.ParseStyleDeclarationList("border-radius: .8em 20px 10px 5px;",
+ source_location_);
+
+ scoped_refptr<cssom::LengthValue> border_top_left_radius =
+ dynamic_cast<cssom::LengthValue*>(
+ style->GetPropertyValue(cssom::kBorderTopLeftRadiusProperty).get());
+ ASSERT_TRUE(border_top_left_radius);
+ EXPECT_FLOAT_EQ(0.8f, border_top_left_radius->value());
+ EXPECT_EQ(cssom::kFontSizesAkaEmUnit, border_top_left_radius->unit());
+
+ scoped_refptr<cssom::LengthValue> border_top_right_radius =
+ dynamic_cast<cssom::LengthValue*>(
+ style->GetPropertyValue(cssom::kBorderTopRightRadiusProperty).get());
+ ASSERT_TRUE(border_top_right_radius);
+ EXPECT_FLOAT_EQ(20.0f, border_top_right_radius->value());
+ EXPECT_EQ(cssom::kPixelsUnit, border_top_right_radius->unit());
+
+ scoped_refptr<cssom::LengthValue> border_bottom_right_radius =
+ dynamic_cast<cssom::LengthValue*>(
+ style->GetPropertyValue(cssom::kBorderBottomRightRadiusProperty)
+ .get());
+ ASSERT_TRUE(border_bottom_right_radius);
+ EXPECT_FLOAT_EQ(10.0f, border_bottom_right_radius->value());
+ EXPECT_EQ(cssom::kPixelsUnit, border_bottom_right_radius->unit());
+
+ scoped_refptr<cssom::LengthValue> border_bottom_left_radius =
+ dynamic_cast<cssom::LengthValue*>(
+ style->GetPropertyValue(cssom::kBorderBottomLeftRadiusProperty)
+ .get());
+ ASSERT_TRUE(border_bottom_left_radius);
+ EXPECT_FLOAT_EQ(5.0f, border_bottom_left_radius->value());
+ EXPECT_EQ(cssom::kPixelsUnit, border_bottom_left_radius->unit());
+}
+
+TEST_F(ParserTest, ParsesBorderTopLeftRadius) {
+ scoped_refptr<cssom::CSSDeclaredStyleData> style =
+ parser_.ParseStyleDeclarationList("border-top-left-radius: 20px;",
+ source_location_);
+
+ scoped_refptr<cssom::LengthValue> border_top_left_radius =
+ dynamic_cast<cssom::LengthValue*>(
+ style->GetPropertyValue(cssom::kBorderTopLeftRadiusProperty).get());
+ ASSERT_TRUE(border_top_left_radius);
+ EXPECT_FLOAT_EQ(20.0f, border_top_left_radius->value());
+ EXPECT_EQ(cssom::kPixelsUnit, border_top_left_radius->unit());
+}
+
+TEST_F(ParserTest, ParsesBorderTopRightRadius) {
+ scoped_refptr<cssom::CSSDeclaredStyleData> style =
+ parser_.ParseStyleDeclarationList("border-top-right-radius: .8em;",
+ source_location_);
+
+ scoped_refptr<cssom::LengthValue> border_top_right_radius =
+ dynamic_cast<cssom::LengthValue*>(
+ style->GetPropertyValue(cssom::kBorderTopRightRadiusProperty).get());
+ ASSERT_TRUE(border_top_right_radius);
+ EXPECT_FLOAT_EQ(0.8f, border_top_right_radius->value());
+ EXPECT_EQ(cssom::kFontSizesAkaEmUnit, border_top_right_radius->unit());
+}
+
+TEST_F(ParserTest, ParsesBorderBottomRightRadius) {
+ scoped_refptr<cssom::CSSDeclaredStyleData> style =
+ parser_.ParseStyleDeclarationList("border-bottom-right-radius: 50px;",
+ source_location_);
+
+ scoped_refptr<cssom::LengthValue> border_bottom_right_radius =
+ dynamic_cast<cssom::LengthValue*>(
+ style->GetPropertyValue(cssom::kBorderBottomRightRadiusProperty)
+ .get());
+ ASSERT_TRUE(border_bottom_right_radius);
+ EXPECT_FLOAT_EQ(50.0f, border_bottom_right_radius->value());
+ EXPECT_EQ(cssom::kPixelsUnit, border_bottom_right_radius->unit());
+}
+
+TEST_F(ParserTest, ParsesBorderBottomLeftRadius) {
+ scoped_refptr<cssom::CSSDeclaredStyleData> style =
+ parser_.ParseStyleDeclarationList("border-bottom-left-radius: .2em;",
+ source_location_);
+
+ scoped_refptr<cssom::LengthValue> border_bottom_left_radius =
+ dynamic_cast<cssom::LengthValue*>(
+ style->GetPropertyValue(cssom::kBorderBottomLeftRadiusProperty)
+ .get());
+ ASSERT_TRUE(border_bottom_left_radius);
+ EXPECT_FLOAT_EQ(0.2f, border_bottom_left_radius->value());
+ EXPECT_EQ(cssom::kFontSizesAkaEmUnit, border_bottom_left_radius->unit());
}
TEST_F(ParserTest, ParsesBoxShadowWithNone) {
diff --git a/src/cobalt/css_parser/scanner.cc b/src/cobalt/css_parser/scanner.cc
index b03a7d8..06f6eaa 100644
--- a/src/cobalt/css_parser/scanner.cc
+++ b/src/cobalt/css_parser/scanner.cc
@@ -1856,6 +1856,24 @@
}
return false;
+ case 22:
+ if (IsEqualToCssIdentifier(
+ name.begin,
+ cssom::GetPropertyName(cssom::kBorderTopLeftRadiusProperty))) {
+ *property_name_token = kBorderTopLeftRadiusToken;
+ return true;
+ }
+ return false;
+
+ case 23:
+ if (IsEqualToCssIdentifier(
+ name.begin,
+ cssom::GetPropertyName(cssom::kBorderTopRightRadiusProperty))) {
+ *property_name_token = kBorderTopRightRadiusToken;
+ return true;
+ }
+ return false;
+
case 25:
if (IsEqualToCssIdentifier(
name.begin, cssom::GetPropertyName(
@@ -1869,6 +1887,12 @@
*property_name_token = kAnimationTimingFunctionToken;
return true;
}
+ if (IsEqualToCssIdentifier(
+ name.begin,
+ cssom::GetPropertyName(cssom::kBorderBottomLeftRadiusProperty))) {
+ *property_name_token = kBorderBottomLeftRadiusToken;
+ return true;
+ }
return false;
case 26:
@@ -1878,6 +1902,12 @@
*property_name_token = kTransitionTimingFunctionToken;
return true;
}
+ if (IsEqualToCssIdentifier(
+ name.begin, cssom::GetPropertyName(
+ cssom::kBorderBottomRightRadiusProperty))) {
+ *property_name_token = kBorderBottomRightRadiusToken;
+ return true;
+ }
return false;
}
diff --git a/src/cobalt/cssom/computed_style.cc b/src/cobalt/cssom/computed_style.cc
index c26d8e1..a59143a 100644
--- a/src/cobalt/cssom/computed_style.cc
+++ b/src/cobalt/cssom/computed_style.cc
@@ -2933,7 +2933,10 @@
(*value)->Accept(&background_size_provider);
*value = background_size_provider.computed_background_size();
} break;
- case kBorderRadiusProperty: {
+ case kBorderBottomLeftRadiusProperty:
+ case kBorderBottomRightRadiusProperty:
+ case kBorderTopLeftRadiusProperty:
+ case kBorderTopRightRadiusProperty: {
ComputedBorderRadiusProvider border_radius_provider(
GetFontSize(), GetRootFontSize(), GetViewportSizeOnePercent());
(*value)->Accept(&border_radius_provider);
@@ -3013,6 +3016,7 @@
case kBorderColorProperty:
case kBorderLeftProperty:
case kBorderProperty:
+ case kBorderRadiusProperty:
case kBorderRightProperty:
case kBorderStyleProperty:
case kBorderTopProperty:
@@ -3076,6 +3080,8 @@
case kBackgroundSizeProperty:
case kBorderBottomProperty:
case kBorderBottomColorProperty:
+ case kBorderBottomLeftRadiusProperty:
+ case kBorderBottomRightRadiusProperty:
case kBorderBottomWidthProperty:
case kBorderColorProperty:
case kBorderLeftProperty:
@@ -3088,6 +3094,8 @@
case kBorderStyleProperty:
case kBorderTopProperty:
case kBorderTopColorProperty:
+ case kBorderTopLeftRadiusProperty:
+ case kBorderTopRightRadiusProperty:
case kBorderTopWidthProperty:
case kBorderProperty:
case kBorderWidthProperty:
diff --git a/src/cobalt/cssom/computed_style_test.cc b/src/cobalt/cssom/computed_style_test.cc
index 26e0064..cfa0183 100644
--- a/src/cobalt/cssom/computed_style_test.cc
+++ b/src/cobalt/cssom/computed_style_test.cc
@@ -774,7 +774,8 @@
TEST(PromoteToComputedStyle, BorderRadiusEmToPixel) {
scoped_refptr<CSSComputedStyleData> computed_style(
new CSSComputedStyleData());
- computed_style->set_border_radius(new LengthValue(3, kFontSizesAkaEmUnit));
+ computed_style->set_border_top_left_radius(
+ new LengthValue(3, kFontSizesAkaEmUnit));
scoped_refptr<CSSComputedStyleData> parent_computed_style(
new CSSComputedStyleData());
@@ -784,10 +785,12 @@
PromoteToComputedStyle(computed_style, parent_computed_style_declaration,
parent_computed_style, math::Size(), NULL);
- LengthValue* border_radius = base::polymorphic_downcast<LengthValue*>(
- computed_style->border_radius().get());
- EXPECT_FLOAT_EQ(48.0f, border_radius->value());
- EXPECT_EQ(kPixelsUnit, border_radius->unit());
+ LengthValue* border_top_left_radius =
+ base::polymorphic_downcast<LengthValue*>(
+ computed_style->border_top_left_radius().get());
+ ASSERT_TRUE(border_top_left_radius);
+ EXPECT_FLOAT_EQ(48.0f, border_top_left_radius->value());
+ EXPECT_EQ(kPixelsUnit, border_top_left_radius->unit());
}
TEST(PromoteToComputedStyle, BorderColorWithInitialValue) {
diff --git a/src/cobalt/cssom/css_computed_style_data.cc b/src/cobalt/cssom/css_computed_style_data.cc
index e0d75a2..492e046 100644
--- a/src/cobalt/cssom/css_computed_style_data.cc
+++ b/src/cobalt/cssom/css_computed_style_data.cc
@@ -167,19 +167,23 @@
case kBackgroundProperty:
case kBackgroundRepeatProperty:
case kBackgroundSizeProperty:
- case kBorderBottomStyleProperty:
+ case kBorderBottomLeftRadiusProperty:
case kBorderBottomProperty:
+ case kBorderBottomRightRadiusProperty:
+ case kBorderBottomStyleProperty:
case kBorderColorProperty:
case kBorderLeftProperty:
case kBorderLeftStyleProperty:
case kBorderProperty:
+ case kBorderRadiusProperty:
case kBorderRightProperty:
case kBorderRightStyleProperty:
case kBorderStyleProperty:
+ case kBorderTopLeftRadiusProperty:
case kBorderTopProperty:
+ case kBorderTopRightRadiusProperty:
case kBorderTopStyleProperty:
case kBorderWidthProperty:
- case kBorderRadiusProperty:
case kBottomProperty:
case kBoxShadowProperty:
case kColorProperty:
diff --git a/src/cobalt/cssom/css_computed_style_data.h b/src/cobalt/cssom/css_computed_style_data.h
index ab2c0fc..88d90a6 100644
--- a/src/cobalt/cssom/css_computed_style_data.h
+++ b/src/cobalt/cssom/css_computed_style_data.h
@@ -275,11 +275,38 @@
SetPropertyValue(kBorderLeftWidthProperty, border_left_width);
}
- const scoped_refptr<PropertyValue>& border_radius() const {
- return GetPropertyValueReference(kBorderRadiusProperty);
+ const scoped_refptr<PropertyValue>& border_top_left_radius() const {
+ return GetPropertyValueReference(kBorderTopLeftRadiusProperty);
}
- void set_border_radius(const scoped_refptr<PropertyValue>& border_radius) {
- SetPropertyValue(kBorderRadiusProperty, border_radius);
+ void set_border_top_left_radius(
+ const scoped_refptr<PropertyValue>& border_top_left_radius) {
+ SetPropertyValue(kBorderTopLeftRadiusProperty, border_top_left_radius);
+ }
+
+ const scoped_refptr<PropertyValue>& border_top_right_radius() const {
+ return GetPropertyValueReference(kBorderTopRightRadiusProperty);
+ }
+ void set_border_top_right_radius(
+ const scoped_refptr<PropertyValue>& border_top_right_radius) {
+ SetPropertyValue(kBorderTopRightRadiusProperty, border_top_right_radius);
+ }
+
+ const scoped_refptr<PropertyValue>& border_bottom_right_radius() const {
+ return GetPropertyValueReference(kBorderBottomRightRadiusProperty);
+ }
+ void set_border_bottom_right_radius(
+ const scoped_refptr<PropertyValue>& border_bottom_right_radius) {
+ SetPropertyValue(kBorderBottomRightRadiusProperty,
+ border_bottom_right_radius);
+ }
+
+ const scoped_refptr<PropertyValue>& border_bottom_left_radius() const {
+ return GetPropertyValueReference(kBorderBottomLeftRadiusProperty);
+ }
+ void set_border_bottom_left_radius(
+ const scoped_refptr<PropertyValue>& border_bottom_left_radius) {
+ SetPropertyValue(kBorderBottomLeftRadiusProperty,
+ border_bottom_left_radius);
}
const scoped_refptr<PropertyValue>& bottom() const {
diff --git a/src/cobalt/cssom/css_computed_style_data_test.cc b/src/cobalt/cssom/css_computed_style_data_test.cc
index f7b4f0c..de9ac9d 100644
--- a/src/cobalt/cssom/css_computed_style_data_test.cc
+++ b/src/cobalt/cssom/css_computed_style_data_test.cc
@@ -127,20 +127,69 @@
TEST(CSSComputedStyleDataTest, BorderRadiusSettersAndGettersAreConsistent) {
scoped_refptr<CSSComputedStyleData> style = new CSSComputedStyleData();
- EXPECT_EQ(GetPropertyInitialValue(kBorderRadiusProperty),
- style->border_radius());
- EXPECT_EQ(style->border_radius(),
- style->GetPropertyValue(kBorderRadiusProperty));
+ EXPECT_EQ(GetPropertyInitialValue(kBorderTopLeftRadiusProperty),
+ style->border_top_left_radius());
+ EXPECT_EQ(style->border_top_left_radius(),
+ style->GetPropertyValue(kBorderTopLeftRadiusProperty));
- style->set_border_radius(KeywordValue::GetInitial());
- EXPECT_EQ(KeywordValue::GetInitial(), style->border_radius());
+ style->set_border_top_left_radius(KeywordValue::GetInitial());
+ EXPECT_EQ(KeywordValue::GetInitial(), style->border_top_left_radius());
EXPECT_EQ(KeywordValue::GetInitial(),
- style->GetPropertyValue(kBorderRadiusProperty));
+ style->GetPropertyValue(kBorderTopLeftRadiusProperty));
- style->SetPropertyValue(kBorderRadiusProperty, KeywordValue::GetInherit());
- EXPECT_EQ(KeywordValue::GetInherit(), style->border_radius());
+ style->SetPropertyValue(kBorderTopLeftRadiusProperty,
+ KeywordValue::GetInherit());
+ EXPECT_EQ(KeywordValue::GetInherit(), style->border_top_left_radius());
EXPECT_EQ(KeywordValue::GetInherit(),
- style->GetPropertyValue(kBorderRadiusProperty));
+ style->GetPropertyValue(kBorderTopLeftRadiusProperty));
+
+ EXPECT_EQ(GetPropertyInitialValue(kBorderTopRightRadiusProperty),
+ style->border_top_right_radius());
+ EXPECT_EQ(style->border_top_right_radius(),
+ style->GetPropertyValue(kBorderTopRightRadiusProperty));
+
+ style->set_border_top_right_radius(KeywordValue::GetInitial());
+ EXPECT_EQ(KeywordValue::GetInitial(), style->border_top_right_radius());
+ EXPECT_EQ(KeywordValue::GetInitial(),
+ style->GetPropertyValue(kBorderTopRightRadiusProperty));
+
+ style->SetPropertyValue(kBorderTopRightRadiusProperty,
+ KeywordValue::GetInherit());
+ EXPECT_EQ(KeywordValue::GetInherit(), style->border_top_right_radius());
+ EXPECT_EQ(KeywordValue::GetInherit(),
+ style->GetPropertyValue(kBorderTopRightRadiusProperty));
+
+ EXPECT_EQ(GetPropertyInitialValue(kBorderBottomRightRadiusProperty),
+ style->border_bottom_right_radius());
+ EXPECT_EQ(style->border_bottom_right_radius(),
+ style->GetPropertyValue(kBorderBottomRightRadiusProperty));
+
+ style->set_border_bottom_right_radius(KeywordValue::GetInitial());
+ EXPECT_EQ(KeywordValue::GetInitial(), style->border_bottom_right_radius());
+ EXPECT_EQ(KeywordValue::GetInitial(),
+ style->GetPropertyValue(kBorderBottomRightRadiusProperty));
+
+ style->SetPropertyValue(kBorderBottomRightRadiusProperty,
+ KeywordValue::GetInherit());
+ EXPECT_EQ(KeywordValue::GetInherit(), style->border_bottom_right_radius());
+ EXPECT_EQ(KeywordValue::GetInherit(),
+ style->GetPropertyValue(kBorderBottomRightRadiusProperty));
+
+ EXPECT_EQ(GetPropertyInitialValue(kBorderBottomLeftRadiusProperty),
+ style->border_bottom_left_radius());
+ EXPECT_EQ(style->border_bottom_left_radius(),
+ style->GetPropertyValue(kBorderBottomLeftRadiusProperty));
+
+ style->set_border_bottom_left_radius(KeywordValue::GetInitial());
+ EXPECT_EQ(KeywordValue::GetInitial(), style->border_bottom_left_radius());
+ EXPECT_EQ(KeywordValue::GetInitial(),
+ style->GetPropertyValue(kBorderBottomLeftRadiusProperty));
+
+ style->SetPropertyValue(kBorderBottomLeftRadiusProperty,
+ KeywordValue::GetInherit());
+ EXPECT_EQ(KeywordValue::GetInherit(), style->border_bottom_left_radius());
+ EXPECT_EQ(KeywordValue::GetInherit(),
+ style->GetPropertyValue(kBorderBottomLeftRadiusProperty));
}
TEST(CSSComputedStyleDataTest, BorderTopColorSettersAndGettersAreConsistent) {
diff --git a/src/cobalt/cssom/css_declared_style_data_test.cc b/src/cobalt/cssom/css_declared_style_data_test.cc
index ae9a990..b9b0a5e 100644
--- a/src/cobalt/cssom/css_declared_style_data_test.cc
+++ b/src/cobalt/cssom/css_declared_style_data_test.cc
@@ -85,12 +85,33 @@
TEST(CSSDeclaredStyleDataTest, BorderRadiusSettersAndGettersAreConsistent) {
scoped_refptr<CSSDeclaredStyleData> style = new CSSDeclaredStyleData();
- EXPECT_FALSE(style->GetPropertyValue(kBorderRadiusProperty));
+ EXPECT_FALSE(style->GetPropertyValue(kBorderTopLeftRadiusProperty));
- style->SetPropertyValueAndImportance(kBorderRadiusProperty,
+ style->SetPropertyValueAndImportance(kBorderTopLeftRadiusProperty,
KeywordValue::GetInherit(), false);
EXPECT_EQ(KeywordValue::GetInherit(),
- style->GetPropertyValue(kBorderRadiusProperty));
+ style->GetPropertyValue(kBorderTopLeftRadiusProperty));
+
+ EXPECT_FALSE(style->GetPropertyValue(kBorderTopRightRadiusProperty));
+
+ style->SetPropertyValueAndImportance(kBorderTopRightRadiusProperty,
+ KeywordValue::GetInherit(), false);
+ EXPECT_EQ(KeywordValue::GetInherit(),
+ style->GetPropertyValue(kBorderTopRightRadiusProperty));
+
+ EXPECT_FALSE(style->GetPropertyValue(kBorderBottomRightRadiusProperty));
+
+ style->SetPropertyValueAndImportance(kBorderBottomRightRadiusProperty,
+ KeywordValue::GetInherit(), false);
+ EXPECT_EQ(KeywordValue::GetInherit(),
+ style->GetPropertyValue(kBorderBottomRightRadiusProperty));
+
+ EXPECT_FALSE(style->GetPropertyValue(kBorderBottomLeftRadiusProperty));
+
+ style->SetPropertyValueAndImportance(kBorderBottomLeftRadiusProperty,
+ KeywordValue::GetInherit(), false);
+ EXPECT_EQ(KeywordValue::GetInherit(),
+ style->GetPropertyValue(kBorderBottomLeftRadiusProperty));
}
TEST(CSSDeclaredStyleDataTest, BorderTopColorSettersAndGettersAreConsistent) {
diff --git a/src/cobalt/cssom/css_declared_style_declaration_test.cc b/src/cobalt/cssom/css_declared_style_declaration_test.cc
index 00eb1f1..1975f98 100644
--- a/src/cobalt/cssom/css_declared_style_declaration_test.cc
+++ b/src/cobalt/cssom/css_declared_style_declaration_test.cc
@@ -183,6 +183,38 @@
style->set_border_bottom_color(border_bottom_color, NULL);
}
+TEST(CSSDeclaredStyleDeclarationTest, BorderBottomLeftRadiusSetter) {
+ testing::MockCSSParser css_parser;
+ scoped_refptr<CSSDeclaredStyleDeclaration> style =
+ new CSSDeclaredStyleDeclaration(&css_parser);
+
+ const std::string border_bottom_left_radius = "0.2em";
+ MockMutationObserver observer;
+ style->set_mutation_observer(&observer);
+
+ EXPECT_CALL(css_parser, ParsePropertyIntoDeclarationData(
+ GetPropertyName(kBorderBottomLeftRadiusProperty),
+ border_bottom_left_radius, _, _));
+ EXPECT_CALL(observer, OnCSSMutation()).Times(1);
+ style->set_border_bottom_left_radius(border_bottom_left_radius, NULL);
+}
+
+TEST(CSSDeclaredStyleDeclarationTest, BorderBottomRightRadiusSetter) {
+ testing::MockCSSParser css_parser;
+ scoped_refptr<CSSDeclaredStyleDeclaration> style =
+ new CSSDeclaredStyleDeclaration(&css_parser);
+
+ const std::string border_bottom_right_radius = "0.2em";
+ MockMutationObserver observer;
+ style->set_mutation_observer(&observer);
+
+ EXPECT_CALL(css_parser, ParsePropertyIntoDeclarationData(
+ GetPropertyName(kBorderBottomRightRadiusProperty),
+ border_bottom_right_radius, _, _));
+ EXPECT_CALL(observer, OnCSSMutation()).Times(1);
+ style->set_border_bottom_right_radius(border_bottom_right_radius, NULL);
+}
+
TEST(CSSDeclaredStyleDeclarationTest, BorderBottomStyleSetter) {
testing::MockCSSParser css_parser;
scoped_refptr<CSSDeclaredStyleDeclaration> style =
@@ -391,6 +423,38 @@
style->set_border_style(border_style, NULL);
}
+TEST(CSSDeclaredStyleDeclarationTest, BorderTopLeftRadiusSetter) {
+ testing::MockCSSParser css_parser;
+ scoped_refptr<CSSDeclaredStyleDeclaration> style =
+ new CSSDeclaredStyleDeclaration(&css_parser);
+
+ const std::string border_top_left_radius = "0.2em";
+ MockMutationObserver observer;
+ style->set_mutation_observer(&observer);
+
+ EXPECT_CALL(css_parser, ParsePropertyIntoDeclarationData(
+ GetPropertyName(kBorderTopLeftRadiusProperty),
+ border_top_left_radius, _, _));
+ EXPECT_CALL(observer, OnCSSMutation()).Times(1);
+ style->set_border_top_left_radius(border_top_left_radius, NULL);
+}
+
+TEST(CSSDeclaredStyleDeclarationTest, BorderTopRightRadiusSetter) {
+ testing::MockCSSParser css_parser;
+ scoped_refptr<CSSDeclaredStyleDeclaration> style =
+ new CSSDeclaredStyleDeclaration(&css_parser);
+
+ const std::string border_top_right_radius = "0.2em";
+ MockMutationObserver observer;
+ style->set_mutation_observer(&observer);
+
+ EXPECT_CALL(css_parser, ParsePropertyIntoDeclarationData(
+ GetPropertyName(kBorderTopRightRadiusProperty),
+ border_top_right_radius, _, _));
+ EXPECT_CALL(observer, OnCSSMutation()).Times(1);
+ style->set_border_top_right_radius(border_top_right_radius, NULL);
+}
+
TEST(CSSDeclaredStyleDeclarationTest, BorderTopSetter) {
testing::MockCSSParser css_parser;
scoped_refptr<CSSDeclaredStyleDeclaration> style =
diff --git a/src/cobalt/cssom/css_style_declaration.cc b/src/cobalt/cssom/css_style_declaration.cc
index 7736040..e2e62fd 100644
--- a/src/cobalt/cssom/css_style_declaration.cc
+++ b/src/cobalt/cssom/css_style_declaration.cc
@@ -428,6 +428,54 @@
exception_state);
}
+std::string CSSStyleDeclaration::border_top_left_radius(
+ script::ExceptionState* /*exception_state*/) const {
+ return GetDeclaredPropertyValueStringByKey(kBorderTopLeftRadiusProperty);
+}
+
+void CSSStyleDeclaration::set_border_top_left_radius(
+ const std::string& border_top_left_radius,
+ script::ExceptionState* exception_state) {
+ SetPropertyValueStringByKey(kBorderTopLeftRadiusProperty,
+ border_top_left_radius, exception_state);
+}
+
+std::string CSSStyleDeclaration::border_top_right_radius(
+ script::ExceptionState* /*exception_state*/) const {
+ return GetDeclaredPropertyValueStringByKey(kBorderTopRightRadiusProperty);
+}
+
+void CSSStyleDeclaration::set_border_top_right_radius(
+ const std::string& border_top_right_radius,
+ script::ExceptionState* exception_state) {
+ SetPropertyValueStringByKey(kBorderTopRightRadiusProperty,
+ border_top_right_radius, exception_state);
+}
+
+std::string CSSStyleDeclaration::border_bottom_right_radius(
+ script::ExceptionState* /*exception_state*/) const {
+ return GetDeclaredPropertyValueStringByKey(kBorderBottomRightRadiusProperty);
+}
+
+void CSSStyleDeclaration::set_border_bottom_right_radius(
+ const std::string& border_bottom_right_radius,
+ script::ExceptionState* exception_state) {
+ SetPropertyValueStringByKey(kBorderBottomRightRadiusProperty,
+ border_bottom_right_radius, exception_state);
+}
+
+std::string CSSStyleDeclaration::border_bottom_left_radius(
+ script::ExceptionState* /*exception_state*/) const {
+ return GetDeclaredPropertyValueStringByKey(kBorderBottomLeftRadiusProperty);
+}
+
+void CSSStyleDeclaration::set_border_bottom_left_radius(
+ const std::string& border_bottom_left_radius,
+ script::ExceptionState* exception_state) {
+ SetPropertyValueStringByKey(kBorderBottomLeftRadiusProperty,
+ border_bottom_left_radius, exception_state);
+}
+
std::string CSSStyleDeclaration::bottom(
script::ExceptionState* /*exception_state*/) const {
return GetDeclaredPropertyValueStringByKey(kBottomProperty);
diff --git a/src/cobalt/cssom/css_style_declaration.h b/src/cobalt/cssom/css_style_declaration.h
index 42d159d..0cda61a 100644
--- a/src/cobalt/cssom/css_style_declaration.h
+++ b/src/cobalt/cssom/css_style_declaration.h
@@ -116,6 +116,18 @@
void set_border_bottom_color(const std::string& border_bottom_color,
script::ExceptionState* exception_state);
+ std::string border_bottom_left_radius(
+ script::ExceptionState* exception_state) const;
+ void set_border_bottom_left_radius(
+ const std::string& border_bottom_left_radius,
+ script::ExceptionState* exception_state);
+
+ std::string border_bottom_right_radius(
+ script::ExceptionState* exception_state) const;
+ void set_border_bottom_right_radius(
+ const std::string& border_bottom_right_radius,
+ script::ExceptionState* exception_state);
+
std::string border_bottom_style(
script::ExceptionState* exception_state) const;
void set_border_bottom_style(const std::string& border_bottom_style,
@@ -174,6 +186,16 @@
void set_border_top_color(const std::string& border_top_color,
script::ExceptionState* exception_state);
+ std::string border_top_left_radius(
+ script::ExceptionState* exception_state) const;
+ void set_border_top_left_radius(const std::string& border_top_left_radius,
+ script::ExceptionState* exception_state);
+
+ std::string border_top_right_radius(
+ script::ExceptionState* exception_state) const;
+ void set_border_top_right_radius(const std::string& border_top_right_radius,
+ script::ExceptionState* exception_state);
+
std::string border_top_style(script::ExceptionState* exception_state) const;
void set_border_top_style(const std::string& border_top_style,
script::ExceptionState* exception_state);
diff --git a/src/cobalt/cssom/css_style_declaration.idl b/src/cobalt/cssom/css_style_declaration.idl
index 3a92ed1..25101cf 100644
--- a/src/cobalt/cssom/css_style_declaration.idl
+++ b/src/cobalt/cssom/css_style_declaration.idl
@@ -33,6 +33,8 @@
[TreatNullAs=EmptyString, RaisesException] attribute DOMString border;
[TreatNullAs=EmptyString, RaisesException] attribute DOMString borderBottom;
[TreatNullAs=EmptyString, RaisesException] attribute DOMString borderBottomColor;
+ [TreatNullAs=EmptyString, RaisesException] attribute DOMString borderBottomLeftRadius;
+ [TreatNullAs=EmptyString, RaisesException] attribute DOMString borderBottomRightRadius;
[TreatNullAs=EmptyString, RaisesException] attribute DOMString borderBottomStyle;
[TreatNullAs=EmptyString, RaisesException] attribute DOMString borderBottomWidth;
[TreatNullAs=EmptyString, RaisesException] attribute DOMString borderColor;
@@ -48,6 +50,8 @@
[TreatNullAs=EmptyString, RaisesException] attribute DOMString borderStyle;
[TreatNullAs=EmptyString, RaisesException] attribute DOMString borderTop;
[TreatNullAs=EmptyString, RaisesException] attribute DOMString borderTopColor;
+ [TreatNullAs=EmptyString, RaisesException] attribute DOMString borderTopLeftRadius;
+ [TreatNullAs=EmptyString, RaisesException] attribute DOMString borderTopRightRadius;
[TreatNullAs=EmptyString, RaisesException] attribute DOMString borderTopStyle;
[TreatNullAs=EmptyString, RaisesException] attribute DOMString borderTopWidth;
[TreatNullAs=EmptyString, RaisesException] attribute DOMString borderWidth;
diff --git a/src/cobalt/cssom/property_definitions.cc b/src/cobalt/cssom/property_definitions.cc
index ac7a1cf..eced1da 100644
--- a/src/cobalt/cssom/property_definitions.cc
+++ b/src/cobalt/cssom/property_definitions.cc
@@ -344,12 +344,30 @@
kImpactsBoxSizesYes, kImpactsBoxCrossReferencesNo,
new LengthValue(3, kPixelsUnit));
- // Cobalt only support a single length value that applies to all borders.
// https://www.w3.org/TR/css3-background/#the-border-radius
+ SetPropertyDefinition(kBorderTopLeftRadiusProperty, "border-top-left-radius",
+ kInheritedNo, kAnimatableNo,
+ kImpactsChildDeclaredStyleNo, kImpactsBoxGenerationNo,
+ kImpactsBoxSizesNo, kImpactsBoxCrossReferencesNo,
+ new LengthValue(0, kPixelsUnit));
+
+ SetPropertyDefinition(kBorderTopRightRadiusProperty,
+ "border-top-right-radius", kInheritedNo, kAnimatableNo,
+ kImpactsChildDeclaredStyleNo, kImpactsBoxGenerationNo,
+ kImpactsBoxSizesNo, kImpactsBoxCrossReferencesNo,
+ new LengthValue(0, kPixelsUnit));
+
SetPropertyDefinition(
- kBorderRadiusProperty, "border-radius", kInheritedNo, kAnimatableNo,
- kImpactsChildDeclaredStyleNo, kImpactsBoxGenerationNo, kImpactsBoxSizesNo,
- kImpactsBoxCrossReferencesNo, new LengthValue(0, kPixelsUnit));
+ kBorderBottomRightRadiusProperty, "border-bottom-right-radius",
+ kInheritedNo, kAnimatableNo, kImpactsChildDeclaredStyleNo,
+ kImpactsBoxGenerationNo, kImpactsBoxSizesNo, kImpactsBoxCrossReferencesNo,
+ new LengthValue(0, kPixelsUnit));
+
+ SetPropertyDefinition(
+ kBorderBottomLeftRadiusProperty, "border-bottom-left-radius",
+ kInheritedNo, kAnimatableNo, kImpactsChildDeclaredStyleNo,
+ kImpactsBoxGenerationNo, kImpactsBoxSizesNo, kImpactsBoxCrossReferencesNo,
+ new LengthValue(0, kPixelsUnit));
// https://www.w3.org/TR/CSS2/visuren.html#propdef-bottom
SetPropertyDefinition(kBottomProperty, "bottom", kInheritedNo, kAnimatableNo,
@@ -780,6 +798,15 @@
SetShorthandPropertyDefinition(kBorderWidthProperty, "border-width",
border_width_longhand_properties);
+ // https://www.w3.org/TR/css3-background/#border-radius
+ LonghandPropertySet border_radius_longhand_properties;
+ border_radius_longhand_properties.insert(kBorderTopLeftRadiusProperty);
+ border_radius_longhand_properties.insert(kBorderTopRightRadiusProperty);
+ border_radius_longhand_properties.insert(kBorderBottomRightRadiusProperty);
+ border_radius_longhand_properties.insert(kBorderBottomLeftRadiusProperty);
+ SetShorthandPropertyDefinition(kBorderRadiusProperty, "border-radius",
+ border_radius_longhand_properties);
+
// https://www.w3.org/TR/css3-background/#border
LonghandPropertySet border_longhand_properties;
border_longhand_properties.insert(kBorderColorProperty);
@@ -1423,6 +1450,20 @@
}
return kNoneProperty;
+ case 22:
+ if (LowerCaseEqualsASCII(property_name,
+ GetPropertyName(kBorderTopLeftRadiusProperty))) {
+ return kBorderTopLeftRadiusProperty;
+ }
+ return kNoneProperty;
+
+ case 23:
+ if (LowerCaseEqualsASCII(
+ property_name, GetPropertyName(kBorderTopRightRadiusProperty))) {
+ return kBorderTopRightRadiusProperty;
+ }
+ return kNoneProperty;
+
case 25:
if (LowerCaseEqualsASCII(
property_name,
@@ -1434,11 +1475,21 @@
GetPropertyName(kAnimationTimingFunctionProperty))) {
return kAnimationTimingFunctionProperty;
}
+ if (LowerCaseEqualsASCII(
+ property_name,
+ GetPropertyName(kBorderBottomLeftRadiusProperty))) {
+ return kBorderBottomLeftRadiusProperty;
+ }
return kNoneProperty;
case 26:
if (LowerCaseEqualsASCII(
property_name,
+ GetPropertyName(kBorderBottomRightRadiusProperty))) {
+ return kBorderBottomRightRadiusProperty;
+ }
+ if (LowerCaseEqualsASCII(
+ property_name,
GetPropertyName(kTransitionTimingFunctionProperty))) {
return kTransitionTimingFunctionProperty;
}
diff --git a/src/cobalt/cssom/property_definitions.h b/src/cobalt/cssom/property_definitions.h
index 8fbddbe..3ba699a 100644
--- a/src/cobalt/cssom/property_definitions.h
+++ b/src/cobalt/cssom/property_definitions.h
@@ -53,16 +53,19 @@
kBackgroundRepeatProperty,
kBackgroundSizeProperty,
kBorderBottomColorProperty,
+ kBorderBottomLeftRadiusProperty,
+ kBorderBottomRightRadiusProperty,
kBorderBottomStyleProperty,
kBorderBottomWidthProperty,
kBorderLeftColorProperty,
kBorderLeftStyleProperty,
kBorderLeftWidthProperty,
- kBorderRadiusProperty,
kBorderRightColorProperty,
kBorderRightStyleProperty,
kBorderRightWidthProperty,
kBorderTopColorProperty,
+ kBorderTopLeftRadiusProperty,
+ kBorderTopRightRadiusProperty,
kBorderTopStyleProperty,
kBorderTopWidthProperty,
kBottomProperty,
@@ -135,6 +138,7 @@
kBorderColorProperty,
kBorderLeftProperty,
kBorderProperty,
+ kBorderRadiusProperty,
kBorderRightProperty,
kBorderStyleProperty,
kBorderTopProperty,
diff --git a/src/cobalt/doc/splash_screen.md b/src/cobalt/doc/splash_screen.md
index 201d5e1..9122555 100644
--- a/src/cobalt/doc/splash_screen.md
+++ b/src/cobalt/doc/splash_screen.md
@@ -76,6 +76,15 @@
self-contained splash screen document. The document must not violate the Content
Security Policy. The splash screen is treated as a script resource by the CSP.
+### Caching implementation requirements
+
+In order to cache the application-provided splash screen, Cobalt will attempt
+to create directories and write files into the directory returned from a call to
+`SbSystemGetPath(kSbSystemPathCacheDirectory, ...)`. Cobalt will expect the
+data that it writes into that directory to persist across process instances.
+Cobalt will also need to read the cached splash screen from the cache directory
+when starting up.
+
## Application-specific splash screens
On systems that plan to support multiple Cobalt-based applications, an
@@ -96,5 +105,3 @@
* `h5vcc-embedded://black_splash_screen.html` - a black splash screen
* `h5vcc-embedded://cobalt_splash_screen.html` - a splash screen showing the
Cobalt logo
- * `h5vcc-embedded://youtube_splash_screen.html` - a splash screen showing the
- YouTube logo
diff --git a/src/cobalt/dom/csp_delegate.cc b/src/cobalt/dom/csp_delegate.cc
index fc9d41f..0bcf6f0 100644
--- a/src/cobalt/dom/csp_delegate.cc
+++ b/src/cobalt/dom/csp_delegate.cc
@@ -25,9 +25,10 @@
CspDelegateSecure::CspDelegateSecure(
scoped_ptr<CspViolationReporter> violation_reporter, const GURL& url,
- const std::string& location_policy,
+ const std::string& location_policy, csp::CSPHeaderPolicy require_csp,
const base::Closure& policy_changed_callback) {
location_policy_ = location_policy;
+ require_csp_ = require_csp;
was_header_received_ = false;
policy_changed_callback_ = policy_changed_callback;
@@ -53,10 +54,15 @@
// we check our default navigation policy, to permit navigation to
// and from the main site and error pages, and disallow everything else.
if (!was_header_received_) {
+ bool should_allow = false;
if (type == kLocation) {
- return csp_->AllowNavigateToSource(url, redirect_status);
+ should_allow = csp_->AllowNavigateToSource(url, redirect_status);
+ }
+ if (require_csp_ == csp::kCSPRequired || should_allow) {
+ return should_allow;
} else {
- return false;
+ DLOG(WARNING) << "Page must include Content-Security-Policy header, it "
+ "will fail to load in production builds of Cobalt!";
}
}
diff --git a/src/cobalt/dom/csp_delegate.h b/src/cobalt/dom/csp_delegate.h
index 2660ea7..17a797c 100644
--- a/src/cobalt/dom/csp_delegate.h
+++ b/src/cobalt/dom/csp_delegate.h
@@ -105,6 +105,7 @@
public:
CspDelegateSecure(scoped_ptr<CspViolationReporter> violation_reporter,
const GURL& url, const std::string& location_policy,
+ csp::CSPHeaderPolicy require_csp,
const base::Closure& policy_changed_callback);
~CspDelegateSecure();
@@ -156,6 +157,9 @@
// in a <meta> tag.
base::Closure policy_changed_callback_;
+ // Whether Cobalt is forbidden to render without receiving CSP header.
+ csp::CSPHeaderPolicy require_csp_;
+
private:
DISALLOW_COPY_AND_ASSIGN(CspDelegateSecure);
};
diff --git a/src/cobalt/dom/csp_delegate_factory.cc b/src/cobalt/dom/csp_delegate_factory.cc
index 55a4f15..e20c061 100644
--- a/src/cobalt/dom/csp_delegate_factory.cc
+++ b/src/cobalt/dom/csp_delegate_factory.cc
@@ -46,6 +46,7 @@
CspDelegate* CreateInsecureDelegate(
scoped_ptr<CspViolationReporter> /*violation_reporter*/,
const GURL& /*url*/, const std::string& /*location_policy*/,
+ csp::CSPHeaderPolicy /*requre_csp*/,
const base::Closure& /*policy_changed_callback*/,
int insecure_allowed_token) {
if (InsecureAllowed(insecure_allowed_token)) {
@@ -58,11 +59,11 @@
CspDelegate* CreateSecureDelegate(
scoped_ptr<CspViolationReporter> violation_reporter, const GURL& url,
- const std::string& location_policy,
+ const std::string& location_policy, csp::CSPHeaderPolicy require_csp,
const base::Closure& policy_changed_callback,
int /*insecure_allowed_token*/) {
return new CspDelegateSecure(violation_reporter.Pass(), url, location_policy,
- policy_changed_callback);
+ require_csp, policy_changed_callback);
}
} // namespace
@@ -86,11 +87,11 @@
scoped_ptr<CspDelegate> CspDelegateFactory::Create(
CspEnforcementType type,
scoped_ptr<CspViolationReporter> violation_reporter, const GURL& url,
- const std::string& location_policy,
+ const std::string& location_policy, csp::CSPHeaderPolicy require_csp,
const base::Closure& policy_changed_callback, int insecure_allowed_token) {
- scoped_ptr<CspDelegate> delegate(
- method_[type](violation_reporter.Pass(), url, location_policy,
- policy_changed_callback, insecure_allowed_token));
+ scoped_ptr<CspDelegate> delegate(method_[type](
+ violation_reporter.Pass(), url, location_policy, require_csp,
+ policy_changed_callback, insecure_allowed_token));
return delegate.Pass();
}
diff --git a/src/cobalt/dom/csp_delegate_factory.h b/src/cobalt/dom/csp_delegate_factory.h
index d7f3275..c732d37 100644
--- a/src/cobalt/dom/csp_delegate_factory.h
+++ b/src/cobalt/dom/csp_delegate_factory.h
@@ -21,6 +21,7 @@
#include "base/gtest_prod_util.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/singleton.h"
+#include "cobalt/csp/content_security_policy.h"
#include "cobalt/dom/csp_delegate_type.h"
#include "googleurl/src/gurl.h"
@@ -43,13 +44,13 @@
scoped_ptr<CspDelegate> Create(
CspEnforcementType type,
scoped_ptr<CspViolationReporter> violation_reporter, const GURL& url,
- const std::string& location_policy,
+ const std::string& location_policy, csp::CSPHeaderPolicy require_csp,
const base::Closure& policy_changed_callback,
int insecure_allowed_token = 0);
typedef CspDelegate* (*CspDelegateCreator)(
scoped_ptr<CspViolationReporter> violation_reporter, const GURL&,
- const std::string&, const base::Closure&, int);
+ const std::string&, csp::CSPHeaderPolicy, const base::Closure&, int);
#if !defined(COBALT_FORCE_CSP)
// Allow tests to have the factory create a different delegate type.
diff --git a/src/cobalt/dom/csp_delegate_test.cc b/src/cobalt/dom/csp_delegate_test.cc
index fccdcaf..f1df142 100644
--- a/src/cobalt/dom/csp_delegate_test.cc
+++ b/src/cobalt/dom/csp_delegate_test.cc
@@ -107,8 +107,9 @@
mock_reporter_ = new StrictMock<MockViolationReporter>();
scoped_ptr<CspViolationReporter> reporter(mock_reporter_);
- csp_delegate_.reset(new CspDelegateSecure(
- reporter.Pass(), origin, default_navigation_policy, base::Closure()));
+ csp_delegate_.reset(
+ new CspDelegateSecure(reporter.Pass(), origin, default_navigation_policy,
+ csp::kCSPRequired, base::Closure()));
std::string policy =
base::StringPrintf("default-src none; %s 'self'", GetParam().directive);
csp_delegate_->OnReceiveHeader(policy, csp::kHeaderTypeEnforce,
@@ -138,7 +139,7 @@
TEST(CspDelegateFactoryTest, Secure) {
scoped_ptr<CspDelegate> delegate = CspDelegateFactory::GetInstance()->Create(
kCspEnforcementEnable, scoped_ptr<CspViolationReporter>(), GURL(),
- std::string(), base::Closure());
+ std::string(), csp::kCSPRequired, base::Closure());
EXPECT_TRUE(delegate != NULL);
}
@@ -151,7 +152,7 @@
scoped_ptr<CspDelegate> delegate =
CspDelegateFactory::GetInstance()->Create(
kCspEnforcementDisable, scoped_ptr<CspViolationReporter>(), GURL(),
- std::string(), base::Closure());
+ std::string(), csp::kCSPRequired, base::Closure());
scoped_ptr<CspDelegate> empty_delegate;
EXPECT_EQ(empty_delegate, delegate.get());
@@ -165,7 +166,7 @@
int token = CspDelegateFactory::GetInstance()->GetInsecureAllowedToken();
scoped_ptr<CspDelegate> delegate = CspDelegateFactory::GetInstance()->Create(
kCspEnforcementDisable, scoped_ptr<CspViolationReporter>(), GURL(),
- std::string(), base::Closure(), token);
+ std::string(), csp::kCSPRequired, base::Closure(), token);
EXPECT_TRUE(delegate != NULL);
}
diff --git a/src/cobalt/dom/custom_event_test.cc b/src/cobalt/dom/custom_event_test.cc
index d8b4c42..65c85c1 100644
--- a/src/cobalt/dom/custom_event_test.cc
+++ b/src/cobalt/dom/custom_event_test.cc
@@ -70,13 +70,12 @@
base::Bind(&MockErrorCallback::Run,
base::Unretained(&mock_error_callback_)),
NULL, network_bridge::PostSender(),
- std::string() /* default security policy */, kCspEnforcementEnable,
- base::Closure() /* csp_policy_changed */,
+ std::string() /* default security policy */, csp::kCSPRequired,
+ kCspEnforcementEnable, base::Closure() /* csp_policy_changed */,
base::Closure() /* ran_animation_frame_callbacks */,
- base::Closure() /* window_close */,
+ dom::Window::CloseCallback() /* window_close */,
base::Closure() /* window_minimize */, NULL, NULL)) {
- engine_ = script::JavaScriptEngine::CreateEngine(
- script::JavaScriptEngine::Options());
+ engine_ = script::JavaScriptEngine::CreateEngine();
global_environment_ = engine_->CreateGlobalEnvironment();
global_environment_->CreateGlobalObject(window_,
environment_settings_.get());
diff --git a/src/cobalt/dom/document.cc b/src/cobalt/dom/document.cc
index fa07b55..211b221 100644
--- a/src/cobalt/dom/document.cc
+++ b/src/cobalt/dom/document.cc
@@ -107,7 +107,7 @@
csp_delegate_ =
CspDelegateFactory::GetInstance()
->Create(options.csp_enforcement_mode, violation_reporter.Pass(),
- options.url, options.location_policy,
+ options.url, options.location_policy, options.require_csp,
options.csp_policy_changed_callback,
options.csp_insecure_allowed_token)
.Pass();
diff --git a/src/cobalt/dom/document.h b/src/cobalt/dom/document.h
index 9a6c527..42c824f 100644
--- a/src/cobalt/dom/document.h
+++ b/src/cobalt/dom/document.h
@@ -111,6 +111,7 @@
network_bridge::CookieJar* cookie_jar,
const network_bridge::PostSender& post_sender,
const std::string& location_policy,
+ csp::CSPHeaderPolicy require_csp,
CspEnforcementType csp_enforcement_mode,
const base::Closure& csp_policy_changed_callback,
int csp_insecure_allowed_token = 0, int dom_max_element_depth = 0)
@@ -124,6 +125,7 @@
cookie_jar(cookie_jar),
post_sender(post_sender),
location_policy(location_policy),
+ require_csp(require_csp),
csp_enforcement_mode(csp_enforcement_mode),
csp_policy_changed_callback(csp_policy_changed_callback),
csp_insecure_allowed_token(csp_insecure_allowed_token),
@@ -139,6 +141,7 @@
network_bridge::CookieJar* cookie_jar;
network_bridge::PostSender post_sender;
std::string location_policy;
+ csp::CSPHeaderPolicy require_csp;
CspEnforcementType csp_enforcement_mode;
base::Closure csp_policy_changed_callback;
int csp_insecure_allowed_token;
diff --git a/src/cobalt/dom/error_event_test.cc b/src/cobalt/dom/error_event_test.cc
index b8ead45..40a51d2 100644
--- a/src/cobalt/dom/error_event_test.cc
+++ b/src/cobalt/dom/error_event_test.cc
@@ -70,13 +70,12 @@
base::Bind(&MockErrorCallback::Run,
base::Unretained(&mock_error_callback_)),
NULL, network_bridge::PostSender(),
- std::string() /* default security policy */, kCspEnforcementEnable,
- base::Closure() /* csp_policy_changed */,
+ std::string() /* default security policy */, csp::kCSPRequired,
+ kCspEnforcementEnable, base::Closure() /* csp_policy_changed */,
base::Closure() /* ran_animation_frame_callbacks */,
- base::Closure() /* window_close */,
+ dom::Window::CloseCallback() /* window_close */,
base::Closure() /* window_minimize */, NULL, NULL)) {
- engine_ = script::JavaScriptEngine::CreateEngine(
- script::JavaScriptEngine::Options());
+ engine_ = script::JavaScriptEngine::CreateEngine();
global_environment_ = engine_->CreateGlobalEnvironment();
global_environment_->CreateGlobalObject(window_,
environment_settings_.get());
diff --git a/src/cobalt/dom/testing/stub_window.h b/src/cobalt/dom/testing/stub_window.h
index 2b01566..32ef4f9 100644
--- a/src/cobalt/dom/testing/stub_window.h
+++ b/src/cobalt/dom/testing/stub_window.h
@@ -59,10 +59,10 @@
dom_stat_tracker_.get(), url_, "", "en-US",
base::Callback<void(const GURL&)>(), base::Bind(&StubErrorCallback),
NULL, network_bridge::PostSender(),
- std::string() /* default security policy */, dom::kCspEnforcementEnable,
- base::Closure() /* csp_policy_changed */,
+ std::string() /* default security policy */, csp::kCSPRequired,
+ dom::kCspEnforcementEnable, base::Closure() /* csp_policy_changed */,
base::Closure() /* ran_animation_frame_callbacks */,
- base::Closure() /* window_close */,
+ dom::Window::CloseCallback() /* window_close */,
base::Closure() /* window_minimize */, NULL, NULL);
global_environment_->CreateGlobalObject(window_, &environment_settings_);
}
diff --git a/src/cobalt/dom/window.cc b/src/cobalt/dom/window.cc
index 07b2f6d..25af450 100644
--- a/src/cobalt/dom/window.cc
+++ b/src/cobalt/dom/window.cc
@@ -99,10 +99,11 @@
network_bridge::CookieJar* cookie_jar,
const network_bridge::PostSender& post_sender,
const std::string& default_security_policy,
+ csp::CSPHeaderPolicy require_csp,
CspEnforcementType csp_enforcement_mode,
const base::Closure& csp_policy_changed_callback,
const base::Closure& ran_animation_frame_callbacks_callback,
- const base::Closure& window_close_callback,
+ const CloseCallback& window_close_callback,
const base::Closure& window_minimize_callback,
const scoped_refptr<input::Camera3D>& camera_3d,
const scoped_refptr<MediaSession>& media_session,
@@ -138,7 +139,7 @@
performance_->timing()->GetNavigationStartClock(),
navigation_callback, ParseUserAgentStyleSheet(css_parser),
math::Size(width_, height_), cookie_jar, post_sender,
- default_security_policy, csp_enforcement_mode,
+ default_security_policy, require_csp, csp_enforcement_mode,
csp_policy_changed_callback, csp_insecure_allowed_token,
dom_max_element_depth)))),
document_loader_(NULL),
@@ -202,7 +203,8 @@
void Window::Close() {
LOG(INFO) << __func__;
if (!window_close_callback_.is_null()) {
- window_close_callback_.Run();
+ window_close_callback_.Run(
+ performance_->timing()->GetNavigationStartClock()->Now());
}
}
diff --git a/src/cobalt/dom/window.h b/src/cobalt/dom/window.h
index 49c5135..48f44ff 100644
--- a/src/cobalt/dom/window.h
+++ b/src/cobalt/dom/window.h
@@ -102,6 +102,10 @@
const base::SourceLocation&, const base::Closure&,
const base::Callback<void(const std::string&)>&)>
HTMLDecoderCreatorCallback;
+ // Callback that will be called when window.close() is called. The
+ // base::TimeDelta parameter will contain the document's timeline time when
+ // close() was called.
+ typedef base::Callback<void(base::TimeDelta)> CloseCallback;
typedef UrlRegistry<MediaSource> MediaSourceRegistry;
enum ClockType {
kClockTypeTestRunner,
@@ -134,10 +138,11 @@
network_bridge::CookieJar* cookie_jar,
const network_bridge::PostSender& post_sender,
const std::string& default_security_policy,
+ csp::CSPHeaderPolicy require_csp,
dom::CspEnforcementType csp_enforcement_mode,
const base::Closure& csp_policy_changed_callback,
const base::Closure& ran_animation_frame_callbacks_callback,
- const base::Closure& window_close_callback,
+ const CloseCallback& window_close_callback,
const base::Closure& window_minimize_callback,
const scoped_refptr<input::Camera3D>& camera_3d,
const scoped_refptr<cobalt::media_session::MediaSession>& media_session,
@@ -393,7 +398,7 @@
scoped_refptr<Screen> screen_;
const base::Closure ran_animation_frame_callbacks_callback_;
- const base::Closure window_close_callback_;
+ const CloseCallback window_close_callback_;
const base::Closure window_minimize_callback_;
base::Callback<bool(const std::string&)> splash_screen_cache_callback_;
diff --git a/src/cobalt/dom/window_test.cc b/src/cobalt/dom/window_test.cc
index a35d5bc..65a8c1d 100644
--- a/src/cobalt/dom/window_test.cc
+++ b/src/cobalt/dom/window_test.cc
@@ -59,10 +59,10 @@
base::Bind(&MockErrorCallback::Run,
base::Unretained(&mock_error_callback_)),
NULL, network_bridge::PostSender(),
- std::string() /* default security policy */, kCspEnforcementEnable,
- base::Closure() /* csp_policy_changed */,
+ std::string() /* default security policy */, csp::kCSPRequired,
+ kCspEnforcementEnable, base::Closure() /* csp_policy_changed */,
base::Closure() /* ran_animation_frame_callbacks */,
- base::Closure() /* window_close */,
+ dom::Window::CloseCallback() /* window_close */,
base::Closure() /* window_minimize */, NULL, NULL)) {}
~WindowTest() OVERRIDE {}
diff --git a/src/cobalt/dom_parser/html_decoder.cc b/src/cobalt/dom_parser/html_decoder.cc
index 1609e9d..7dba201 100644
--- a/src/cobalt/dom_parser/html_decoder.cc
+++ b/src/cobalt/dom_parser/html_decoder.cc
@@ -29,13 +29,14 @@
const int dom_max_element_depth, const base::SourceLocation& input_location,
const base::Closure& done_callback,
const base::Callback<void(const std::string&)>& error_callback,
- const bool should_run_scripts)
+ const bool should_run_scripts, const csp::CSPHeaderPolicy require_csp)
: libxml_html_parser_wrapper_(new LibxmlHTMLParserWrapper(
document, parent_node, reference_node, dom_max_element_depth,
input_location, error_callback, should_run_scripts)),
document_(document),
done_callback_(done_callback),
- should_run_scripts_(should_run_scripts) {}
+ should_run_scripts_(should_run_scripts),
+ require_csp_(require_csp) {}
HTMLDecoder::~HTMLDecoder() {}
@@ -61,7 +62,8 @@
}
csp::ResponseHeaders csp_headers(headers);
- if (document_->csp_delegate()->OnReceiveHeaders(csp_headers)) {
+ if (document_->csp_delegate()->OnReceiveHeaders(csp_headers) ||
+ require_csp_ == csp::kCSPOptional) {
return loader::kLoadResponseContinue;
} else {
DLOG(ERROR) << "Failure receiving Content Security Policy headers";
diff --git a/src/cobalt/dom_parser/html_decoder.h b/src/cobalt/dom_parser/html_decoder.h
index 043ad4f..d9ca8b2 100644
--- a/src/cobalt/dom_parser/html_decoder.h
+++ b/src/cobalt/dom_parser/html_decoder.h
@@ -49,7 +49,8 @@
const base::SourceLocation& input_location,
const base::Closure& done_callback,
const base::Callback<void(const std::string&)>& error_callback,
- const bool should_run_scripts);
+ const bool should_run_scripts,
+ const csp::CSPHeaderPolicy require_csp);
~HTMLDecoder();
@@ -75,6 +76,9 @@
const bool should_run_scripts_;
+ // If Cobalt user forbids rendering Cobalt without csp headers.
+ const csp::CSPHeaderPolicy require_csp_;
+
DISALLOW_COPY_AND_ASSIGN(HTMLDecoder);
};
diff --git a/src/cobalt/dom_parser/html_decoder_test.cc b/src/cobalt/dom_parser/html_decoder_test.cc
index d4e89bb..851aea3 100644
--- a/src/cobalt/dom_parser/html_decoder_test.cc
+++ b/src/cobalt/dom_parser/html_decoder_test.cc
@@ -77,11 +77,12 @@
TEST_F(HTMLDecoderTest, CanParseEmptyDocument) {
const std::string input = "";
- html_decoder_.reset(new HTMLDecoder(
- document_, document_, NULL, kDOMMaxElementDepth, source_location_,
- base::Closure(), base::Bind(&MockErrorCallback::Run,
- base::Unretained(&mock_error_callback_)),
- true));
+ html_decoder_.reset(
+ new HTMLDecoder(document_, document_, NULL, kDOMMaxElementDepth,
+ source_location_, base::Closure(),
+ base::Bind(&MockErrorCallback::Run,
+ base::Unretained(&mock_error_callback_)),
+ true, csp::kCSPRequired));
html_decoder_->DecodeChunk(input.c_str(), input.length());
html_decoder_->Finish();
@@ -100,11 +101,12 @@
TEST_F(HTMLDecoderTest, DISABLED_CanParseDocumentWithOnlyNulls) {
unsigned char temp[] = {0x0, 0x0};
- html_decoder_.reset(new HTMLDecoder(
- document_, document_, NULL, kDOMMaxElementDepth, source_location_,
- base::Closure(), base::Bind(&MockErrorCallback::Run,
- base::Unretained(&mock_error_callback_)),
- true));
+ html_decoder_.reset(
+ new HTMLDecoder(document_, document_, NULL, kDOMMaxElementDepth,
+ source_location_, base::Closure(),
+ base::Bind(&MockErrorCallback::Run,
+ base::Unretained(&mock_error_callback_)),
+ true, csp::kCSPRequired));
html_decoder_->DecodeChunk(reinterpret_cast<char*>(temp), sizeof(temp));
html_decoder_->Finish();
@@ -119,11 +121,12 @@
TEST_F(HTMLDecoderTest, DISABLED_CanParseDocumentWithOnlySpaces) {
const std::string input = " ";
- html_decoder_.reset(new HTMLDecoder(
- document_, document_, NULL, kDOMMaxElementDepth, source_location_,
- base::Closure(), base::Bind(&MockErrorCallback::Run,
- base::Unretained(&mock_error_callback_)),
- true));
+ html_decoder_.reset(
+ new HTMLDecoder(document_, document_, NULL, kDOMMaxElementDepth,
+ source_location_, base::Closure(),
+ base::Bind(&MockErrorCallback::Run,
+ base::Unretained(&mock_error_callback_)),
+ true, csp::kCSPRequired));
html_decoder_->DecodeChunk(input.c_str(), input.length());
html_decoder_->Finish();
@@ -138,11 +141,12 @@
TEST_F(HTMLDecoderTest, DISABLED_CanParseDocumentWithOnlyHTML) {
const std::string input = "<html>";
- html_decoder_.reset(new HTMLDecoder(
- document_, document_, NULL, kDOMMaxElementDepth, source_location_,
- base::Closure(), base::Bind(&MockErrorCallback::Run,
- base::Unretained(&mock_error_callback_)),
- true));
+ html_decoder_.reset(
+ new HTMLDecoder(document_, document_, NULL, kDOMMaxElementDepth,
+ source_location_, base::Closure(),
+ base::Bind(&MockErrorCallback::Run,
+ base::Unretained(&mock_error_callback_)),
+ true, csp::kCSPRequired));
html_decoder_->DecodeChunk(input.c_str(), input.length());
html_decoder_->Finish();
@@ -157,11 +161,12 @@
TEST_F(HTMLDecoderTest, CanParseDocumentWithOnlyBody) {
const std::string input = "<body>";
- html_decoder_.reset(new HTMLDecoder(
- document_, document_, NULL, kDOMMaxElementDepth, source_location_,
- base::Closure(), base::Bind(&MockErrorCallback::Run,
- base::Unretained(&mock_error_callback_)),
- true));
+ html_decoder_.reset(
+ new HTMLDecoder(document_, document_, NULL, kDOMMaxElementDepth,
+ source_location_, base::Closure(),
+ base::Bind(&MockErrorCallback::Run,
+ base::Unretained(&mock_error_callback_)),
+ true, csp::kCSPRequired));
html_decoder_->DecodeChunk(input.c_str(), input.length());
html_decoder_->Finish();
@@ -176,11 +181,12 @@
TEST_F(HTMLDecoderTest, DecodingWholeDocumentShouldAddImpliedTags) {
const std::string input = "<p></p>";
- html_decoder_.reset(new HTMLDecoder(
- document_, document_, NULL, kDOMMaxElementDepth, source_location_,
- base::Closure(), base::Bind(&MockErrorCallback::Run,
- base::Unretained(&mock_error_callback_)),
- true));
+ html_decoder_.reset(
+ new HTMLDecoder(document_, document_, NULL, kDOMMaxElementDepth,
+ source_location_, base::Closure(),
+ base::Bind(&MockErrorCallback::Run,
+ base::Unretained(&mock_error_callback_)),
+ true, csp::kCSPRequired));
html_decoder_->DecodeChunk(input.c_str(), input.length());
html_decoder_->Finish();
@@ -200,11 +206,12 @@
TEST_F(HTMLDecoderTest, DecodingDocumentFragmentShouldNotAddImpliedTags) {
const std::string input = "<p></p>";
- html_decoder_.reset(new HTMLDecoder(
- document_, root_, NULL, kDOMMaxElementDepth, source_location_,
- base::Closure(), base::Bind(&MockErrorCallback::Run,
- base::Unretained(&mock_error_callback_)),
- true));
+ html_decoder_.reset(
+ new HTMLDecoder(document_, root_, NULL, kDOMMaxElementDepth,
+ source_location_, base::Closure(),
+ base::Bind(&MockErrorCallback::Run,
+ base::Unretained(&mock_error_callback_)),
+ true, csp::kCSPRequired));
html_decoder_->DecodeChunk(input.c_str(), input.length());
html_decoder_->Finish();
@@ -216,11 +223,12 @@
TEST_F(HTMLDecoderTest, CanParseAttributesWithAndWithoutValue) {
const std::string input = "<div a b=2 c d></div>";
- html_decoder_.reset(new HTMLDecoder(
- document_, root_, NULL, kDOMMaxElementDepth, source_location_,
- base::Closure(), base::Bind(&MockErrorCallback::Run,
- base::Unretained(&mock_error_callback_)),
- true));
+ html_decoder_.reset(
+ new HTMLDecoder(document_, root_, NULL, kDOMMaxElementDepth,
+ source_location_, base::Closure(),
+ base::Bind(&MockErrorCallback::Run,
+ base::Unretained(&mock_error_callback_)),
+ true, csp::kCSPRequired));
html_decoder_->DecodeChunk(input.c_str(), input.length());
html_decoder_->Finish();
@@ -241,11 +249,12 @@
TEST_F(HTMLDecoderTest, CanParseIncompleteAttributesAssignment) {
const std::string input = "<div a= b=2 c=></div>";
- html_decoder_.reset(new HTMLDecoder(
- document_, root_, NULL, kDOMMaxElementDepth, source_location_,
- base::Closure(), base::Bind(&MockErrorCallback::Run,
- base::Unretained(&mock_error_callback_)),
- true));
+ html_decoder_.reset(
+ new HTMLDecoder(document_, root_, NULL, kDOMMaxElementDepth,
+ source_location_, base::Closure(),
+ base::Bind(&MockErrorCallback::Run,
+ base::Unretained(&mock_error_callback_)),
+ true, csp::kCSPRequired));
html_decoder_->DecodeChunk(input.c_str(), input.length());
html_decoder_->Finish();
@@ -262,11 +271,12 @@
TEST_F(HTMLDecoderTest, CanParseSelfClosingTags) {
const std::string input = "<p><p>";
- html_decoder_.reset(new HTMLDecoder(
- document_, root_, NULL, kDOMMaxElementDepth, source_location_,
- base::Closure(), base::Bind(&MockErrorCallback::Run,
- base::Unretained(&mock_error_callback_)),
- true));
+ html_decoder_.reset(
+ new HTMLDecoder(document_, root_, NULL, kDOMMaxElementDepth,
+ source_location_, base::Closure(),
+ base::Bind(&MockErrorCallback::Run,
+ base::Unretained(&mock_error_callback_)),
+ true, csp::kCSPRequired));
html_decoder_->DecodeChunk(input.c_str(), input.length());
html_decoder_->Finish();
@@ -281,11 +291,12 @@
TEST_F(HTMLDecoderTest, CanParseNormalCharacters) {
const std::string input = "<p>text</p>";
- html_decoder_.reset(new HTMLDecoder(
- document_, root_, NULL, kDOMMaxElementDepth, source_location_,
- base::Closure(), base::Bind(&MockErrorCallback::Run,
- base::Unretained(&mock_error_callback_)),
- true));
+ html_decoder_.reset(
+ new HTMLDecoder(document_, root_, NULL, kDOMMaxElementDepth,
+ source_location_, base::Closure(),
+ base::Bind(&MockErrorCallback::Run,
+ base::Unretained(&mock_error_callback_)),
+ true, csp::kCSPRequired));
html_decoder_->DecodeChunk(input.c_str(), input.length());
html_decoder_->Finish();
@@ -301,11 +312,12 @@
TEST_F(HTMLDecoderTest, ShouldIgnoreNonUTF8Input) {
unsigned char temp[] = {0xff, 0xff};
- html_decoder_.reset(new HTMLDecoder(
- document_, root_, NULL, kDOMMaxElementDepth, source_location_,
- base::Closure(), base::Bind(&MockErrorCallback::Run,
- base::Unretained(&mock_error_callback_)),
- true));
+ html_decoder_.reset(
+ new HTMLDecoder(document_, root_, NULL, kDOMMaxElementDepth,
+ source_location_, base::Closure(),
+ base::Bind(&MockErrorCallback::Run,
+ base::Unretained(&mock_error_callback_)),
+ true, csp::kCSPRequired));
html_decoder_->DecodeChunk(reinterpret_cast<char*>(temp), sizeof(temp));
html_decoder_->Finish();
@@ -315,11 +327,12 @@
// Test a decimal and hex escaped supplementary (not in BMP) character.
TEST_F(HTMLDecoderTest, CanParseEscapedCharacters) {
const std::string input = "<p>💩</p><p>💩</p>";
- html_decoder_.reset(new HTMLDecoder(
- document_, root_, NULL, kDOMMaxElementDepth, source_location_,
- base::Closure(), base::Bind(&MockErrorCallback::Run,
- base::Unretained(&mock_error_callback_)),
- true));
+ html_decoder_.reset(
+ new HTMLDecoder(document_, root_, NULL, kDOMMaxElementDepth,
+ source_location_, base::Closure(),
+ base::Bind(&MockErrorCallback::Run,
+ base::Unretained(&mock_error_callback_)),
+ true, csp::kCSPRequired));
html_decoder_->DecodeChunk(input.c_str(), input.length());
html_decoder_->Finish();
@@ -343,11 +356,12 @@
// Test an escaped invalid Unicode character.
TEST_F(HTMLDecoderTest, CanParseEscapedInvalidUnicodeCharacters) {
const std::string input = "<p></p>";
- html_decoder_.reset(new HTMLDecoder(
- document_, root_, NULL, kDOMMaxElementDepth, source_location_,
- base::Closure(), base::Bind(&MockErrorCallback::Run,
- base::Unretained(&mock_error_callback_)),
- true));
+ html_decoder_.reset(
+ new HTMLDecoder(document_, root_, NULL, kDOMMaxElementDepth,
+ source_location_, base::Closure(),
+ base::Bind(&MockErrorCallback::Run,
+ base::Unretained(&mock_error_callback_)),
+ true, csp::kCSPRequired));
html_decoder_->DecodeChunk(input.c_str(), input.length());
html_decoder_->Finish();
@@ -363,11 +377,12 @@
// Test a UTF8 encoded supplementary (not in BMP) character.
TEST_F(HTMLDecoderTest, CanParseUTF8EncodedSupplementaryCharacters) {
const std::string input = "<p>💩</p>";
- html_decoder_.reset(new HTMLDecoder(
- document_, root_, NULL, kDOMMaxElementDepth, source_location_,
- base::Closure(), base::Bind(&MockErrorCallback::Run,
- base::Unretained(&mock_error_callback_)),
- true));
+ html_decoder_.reset(
+ new HTMLDecoder(document_, root_, NULL, kDOMMaxElementDepth,
+ source_location_, base::Closure(),
+ base::Bind(&MockErrorCallback::Run,
+ base::Unretained(&mock_error_callback_)),
+ true, csp::kCSPRequired));
html_decoder_->DecodeChunk(input.c_str(), input.length());
html_decoder_->Finish();
@@ -386,11 +401,12 @@
for (size_t first_chunk_size = 0; first_chunk_size < input.length();
first_chunk_size++) {
root_ = new dom::Element(document_, base::Token("element"));
- html_decoder_.reset(new HTMLDecoder(
- document_, root_, NULL, kDOMMaxElementDepth, source_location_,
- base::Closure(), base::Bind(&MockErrorCallback::Run,
- base::Unretained(&mock_error_callback_)),
- true));
+ html_decoder_.reset(
+ new HTMLDecoder(document_, root_, NULL, kDOMMaxElementDepth,
+ source_location_, base::Closure(),
+ base::Bind(&MockErrorCallback::Run,
+ base::Unretained(&mock_error_callback_)),
+ true, csp::kCSPRequired));
// This could cut the input in the middle of a UTF8 character.
html_decoder_->DecodeChunk(input.c_str(), first_chunk_size);
@@ -414,11 +430,12 @@
// The current version DOES NOT handle the error as outlined in the link above.
TEST_F(HTMLDecoderTest, CanParseMisnestedTags1) {
const std::string input = "<p>1<b>2<i>3</b>4</i>5</p>";
- html_decoder_.reset(new HTMLDecoder(
- document_, root_, NULL, kDOMMaxElementDepth, source_location_,
- base::Closure(), base::Bind(&MockErrorCallback::Run,
- base::Unretained(&mock_error_callback_)),
- true));
+ html_decoder_.reset(
+ new HTMLDecoder(document_, root_, NULL, kDOMMaxElementDepth,
+ source_location_, base::Closure(),
+ base::Bind(&MockErrorCallback::Run,
+ base::Unretained(&mock_error_callback_)),
+ true, csp::kCSPRequired));
html_decoder_->DecodeChunk(input.c_str(), input.length());
html_decoder_->Finish();
@@ -441,11 +458,12 @@
// The current version DOES NOT handle the error as outlined in the link above.
TEST_F(HTMLDecoderTest, CanParseMisnestedTags2) {
const std::string input = "<b>1<p>2</b>3</p>";
- html_decoder_.reset(new HTMLDecoder(
- document_, root_, NULL, kDOMMaxElementDepth, source_location_,
- base::Closure(), base::Bind(&MockErrorCallback::Run,
- base::Unretained(&mock_error_callback_)),
- true));
+ html_decoder_.reset(
+ new HTMLDecoder(document_, root_, NULL, kDOMMaxElementDepth,
+ source_location_, base::Closure(),
+ base::Bind(&MockErrorCallback::Run,
+ base::Unretained(&mock_error_callback_)),
+ true, csp::kCSPRequired));
html_decoder_->DecodeChunk(input.c_str(), input.length());
html_decoder_->Finish();
@@ -460,11 +478,12 @@
TEST_F(HTMLDecoderTest, TagNamesShouldBeCaseInsensitive) {
const std::string input = "<DIV></DIV>";
- html_decoder_.reset(new HTMLDecoder(
- document_, root_, NULL, kDOMMaxElementDepth, source_location_,
- base::Closure(), base::Bind(&MockErrorCallback::Run,
- base::Unretained(&mock_error_callback_)),
- true));
+ html_decoder_.reset(
+ new HTMLDecoder(document_, root_, NULL, kDOMMaxElementDepth,
+ source_location_, base::Closure(),
+ base::Bind(&MockErrorCallback::Run,
+ base::Unretained(&mock_error_callback_)),
+ true, csp::kCSPRequired));
html_decoder_->DecodeChunk(input.c_str(), input.length());
html_decoder_->Finish();
@@ -475,11 +494,12 @@
TEST_F(HTMLDecoderTest, AttributesShouldBeCaseInsensitive) {
const std::string input = "<div A></div>";
- html_decoder_.reset(new HTMLDecoder(
- document_, root_, NULL, kDOMMaxElementDepth, source_location_,
- base::Closure(), base::Bind(&MockErrorCallback::Run,
- base::Unretained(&mock_error_callback_)),
- true));
+ html_decoder_.reset(
+ new HTMLDecoder(document_, root_, NULL, kDOMMaxElementDepth,
+ source_location_, base::Closure(),
+ base::Bind(&MockErrorCallback::Run,
+ base::Unretained(&mock_error_callback_)),
+ true, csp::kCSPRequired));
html_decoder_->DecodeChunk(input.c_str(), input.length());
html_decoder_->Finish();
@@ -499,11 +519,12 @@
"</head>"
"<body>陈绮贞</body>"
"</html>";
- html_decoder_.reset(new HTMLDecoder(
- document_, document_, NULL, kDOMMaxElementDepth, source_location_,
- base::Closure(), base::Bind(&MockErrorCallback::Run,
- base::Unretained(&mock_error_callback_)),
- true));
+ html_decoder_.reset(
+ new HTMLDecoder(document_, document_, NULL, kDOMMaxElementDepth,
+ source_location_, base::Closure(),
+ base::Bind(&MockErrorCallback::Run,
+ base::Unretained(&mock_error_callback_)),
+ true, csp::kCSPRequired));
html_decoder_->DecodeChunk(input.c_str(), input.length());
html_decoder_->Finish();
diff --git a/src/cobalt/dom_parser/parser.cc b/src/cobalt/dom_parser/parser.cc
index 03150ea..65e4473 100644
--- a/src/cobalt/dom_parser/parser.cc
+++ b/src/cobalt/dom_parser/parser.cc
@@ -31,7 +31,7 @@
new dom::Document(html_element_context);
HTMLDecoder html_decoder(document, document, NULL, dom_max_element_depth_,
input_location, base::Closure(), error_callback_,
- false);
+ false, require_csp_);
html_decoder.DecodeChunk(input.c_str(), input.length());
html_decoder.Finish();
return document;
@@ -57,9 +57,9 @@
const scoped_refptr<dom::Node>& parent_node,
const scoped_refptr<dom::Node>& reference_node,
const base::SourceLocation& input_location) {
- HTMLDecoder html_decoder(document, parent_node, reference_node,
- dom_max_element_depth_, input_location,
- base::Closure(), error_callback_, false);
+ HTMLDecoder html_decoder(
+ document, parent_node, reference_node, dom_max_element_depth_,
+ input_location, base::Closure(), error_callback_, false, require_csp_);
html_decoder.DecodeChunk(input.c_str(), input.length());
html_decoder.Finish();
}
@@ -81,9 +81,9 @@
scoped_ptr<loader::Decoder> Parser::ParseDocumentAsync(
const scoped_refptr<dom::Document>& document,
const base::SourceLocation& input_location) {
- return scoped_ptr<loader::Decoder>(
- new HTMLDecoder(document, document, NULL, dom_max_element_depth_,
- input_location, base::Closure(), error_callback_, true));
+ return scoped_ptr<loader::Decoder>(new HTMLDecoder(
+ document, document, NULL, dom_max_element_depth_, input_location,
+ base::Closure(), error_callback_, true, require_csp_));
}
scoped_ptr<loader::Decoder> Parser::ParseXMLDocumentAsync(
diff --git a/src/cobalt/dom_parser/parser.h b/src/cobalt/dom_parser/parser.h
index 0368850..d4cb9fc 100644
--- a/src/cobalt/dom_parser/parser.h
+++ b/src/cobalt/dom_parser/parser.h
@@ -19,6 +19,7 @@
#include "base/bind.h"
#include "base/callback.h"
+#include "cobalt/csp/content_security_policy.h"
#include "cobalt/dom/parser.h"
namespace cobalt {
@@ -29,15 +30,19 @@
Parser()
: dom_max_element_depth_(kDefaultDOMMaxElementDepth),
ALLOW_THIS_IN_INITIALIZER_LIST(error_callback_(
- base::Bind(&Parser::ErrorCallback, base::Unretained(this)))) {}
+ base::Bind(&Parser::ErrorCallback, base::Unretained(this)))),
+ require_csp_(csp::kCSPRequired) {}
explicit Parser(
const base::Callback<void(const std::string&)>& error_callback)
: dom_max_element_depth_(kDefaultDOMMaxElementDepth),
- error_callback_(error_callback) {}
+ error_callback_(error_callback),
+ require_csp_(csp::kCSPRequired) {}
Parser(const int dom_max_element_depth,
- const base::Callback<void(const std::string&)>& error_callback)
+ const base::Callback<void(const std::string&)>& error_callback,
+ csp::CSPHeaderPolicy require_csp)
: dom_max_element_depth_(dom_max_element_depth),
- error_callback_(error_callback) {}
+ error_callback_(error_callback),
+ require_csp_(require_csp) {}
~Parser() OVERRIDE {}
// From dom::Parser.
@@ -79,6 +84,10 @@
void ErrorCallback(const std::string& error);
+ // Cobalt user can specify if they want to forbid Cobalt rendering without csp
+ // headers.
+ csp::CSPHeaderPolicy require_csp_;
+
DISALLOW_COPY_AND_ASSIGN(Parser);
};
diff --git a/src/cobalt/layout/box.cc b/src/cobalt/layout/box.cc
index ff4edae..38c644f 100644
--- a/src/cobalt/layout/box.cc
+++ b/src/cobalt/layout/box.cc
@@ -52,6 +52,7 @@
using cobalt::render_tree::MatrixTransformNode;
using cobalt::render_tree::OpacityFilter;
using cobalt::render_tree::RectNode;
+using cobalt::render_tree::RoundedCorner;
using cobalt::render_tree::RoundedCorners;
using cobalt::render_tree::ViewportFilter;
using cobalt::render_tree::animations::Animation;
@@ -546,24 +547,21 @@
render_tree::CompositionNode::Builder border_node_builder(border_box_offset);
AnimateNode::Builder animate_node_builder;
- UsedBorderRadiusProvider border_radius_provider(GetBorderBoxSize());
- computed_style()->border_radius()->Accept(&border_radius_provider);
+ base::optional<RoundedCorners> rounded_corners = ComputeRoundedCorners();
// If we have rounded corners and a non-zero border, then we need to compute
// the "inner" rounded corners, as the ones specified by CSS apply to the
// outer border edge.
base::optional<RoundedCorners> padding_rounded_corners_if_different;
- if (border_radius_provider.rounded_corners() && !border_insets_.zero()) {
- padding_rounded_corners_if_different =
- border_radius_provider.rounded_corners()->Inset(math::InsetsF(
- border_insets_.left().toFloat(), border_insets_.top().toFloat(),
- border_insets_.right().toFloat(),
- border_insets_.bottom().toFloat()));
+ if (rounded_corners && !border_insets_.zero()) {
+ padding_rounded_corners_if_different = rounded_corners->Inset(math::InsetsF(
+ border_insets_.left().toFloat(), border_insets_.top().toFloat(),
+ border_insets_.right().toFloat(), border_insets_.bottom().toFloat()));
}
const base::optional<RoundedCorners>& padding_rounded_corners =
padding_rounded_corners_if_different
? padding_rounded_corners_if_different
- : border_radius_provider.rounded_corners();
+ : rounded_corners;
// The painting order is:
// - background color.
@@ -594,10 +592,10 @@
if (background_image_result.node) {
border_node_builder.AddChild(background_image_result.node);
}
- RenderAndAnimateBorder(border_radius_provider.rounded_corners(),
- &border_node_builder, &animate_node_builder);
- RenderAndAnimateBoxShadow(border_radius_provider.rounded_corners(),
- &border_node_builder, &animate_node_builder);
+ RenderAndAnimateBorder(rounded_corners, &border_node_builder,
+ &animate_node_builder);
+ RenderAndAnimateBoxShadow(rounded_corners, &border_node_builder,
+ &animate_node_builder);
}
const bool overflow_hidden =
@@ -1227,6 +1225,55 @@
} // namespace
+base::optional<render_tree::RoundedCorners> Box::ComputeRoundedCorners() {
+ UsedBorderRadiusProvider border_radius_provider(GetBorderBoxSize());
+ render_tree::RoundedCorner border_top_left_radius;
+ render_tree::RoundedCorner border_top_right_radius;
+ render_tree::RoundedCorner border_bottom_right_radius;
+ render_tree::RoundedCorner border_bottom_left_radius;
+
+ computed_style()->border_top_left_radius()->Accept(&border_radius_provider);
+ if (border_radius_provider.rounded_corner()) {
+ border_top_left_radius = render_tree::RoundedCorner(
+ border_radius_provider.rounded_corner()->horizontal,
+ border_radius_provider.rounded_corner()->vertical);
+ }
+
+ computed_style()->border_top_right_radius()->Accept(&border_radius_provider);
+ if (border_radius_provider.rounded_corner()) {
+ border_top_right_radius = render_tree::RoundedCorner(
+ border_radius_provider.rounded_corner()->horizontal,
+ border_radius_provider.rounded_corner()->vertical);
+ }
+
+ computed_style()->border_bottom_right_radius()->Accept(
+ &border_radius_provider);
+ if (border_radius_provider.rounded_corner()) {
+ border_bottom_right_radius = render_tree::RoundedCorner(
+ border_radius_provider.rounded_corner()->horizontal,
+ border_radius_provider.rounded_corner()->vertical);
+ }
+ computed_style()->border_bottom_left_radius()->Accept(
+ &border_radius_provider);
+ if (border_radius_provider.rounded_corner()) {
+ border_bottom_left_radius = render_tree::RoundedCorner(
+ border_radius_provider.rounded_corner()->horizontal,
+ border_radius_provider.rounded_corner()->vertical);
+ }
+
+ base::optional<RoundedCorners> rounded_corners;
+ if (!border_top_left_radius.IsSquare() ||
+ !border_top_right_radius.IsSquare() ||
+ !border_bottom_right_radius.IsSquare() ||
+ !border_bottom_left_radius.IsSquare()) {
+ rounded_corners.emplace(border_top_left_radius, border_top_right_radius,
+ border_bottom_right_radius,
+ border_bottom_left_radius);
+ }
+
+ return rounded_corners;
+}
+
void Box::RenderAndAnimateBoxShadow(
const base::optional<RoundedCorners>& rounded_corners,
CompositionNode::Builder* border_node_builder,
@@ -1501,21 +1548,18 @@
scoped_refptr<render_tree::Node> Box::RenderAndAnimateOverflow(
const scoped_refptr<render_tree::Node>& content_node,
const math::Vector2dF& border_offset) {
- UsedBorderRadiusProvider border_radius_provider(GetBorderBoxSize());
- computed_style()->border_radius()->Accept(&border_radius_provider);
+ base::optional<RoundedCorners> rounded_corners = ComputeRoundedCorners();
base::optional<RoundedCorners> padding_rounded_corners_if_different;
- if (border_radius_provider.rounded_corners() && !border_insets_.zero()) {
- padding_rounded_corners_if_different =
- border_radius_provider.rounded_corners()->Inset(math::InsetsF(
- border_insets_.left().toFloat(), border_insets_.top().toFloat(),
- border_insets_.right().toFloat(),
- border_insets_.bottom().toFloat()));
+ if (rounded_corners && !border_insets_.zero()) {
+ padding_rounded_corners_if_different = rounded_corners->Inset(math::InsetsF(
+ border_insets_.left().toFloat(), border_insets_.top().toFloat(),
+ border_insets_.right().toFloat(), border_insets_.bottom().toFloat()));
}
const base::optional<RoundedCorners>& padding_rounded_corners =
padding_rounded_corners_if_different
? padding_rounded_corners_if_different
- : border_radius_provider.rounded_corners();
+ : rounded_corners;
return RenderAndAnimateOverflow(padding_rounded_corners, content_node, NULL,
border_offset);
diff --git a/src/cobalt/layout/box.h b/src/cobalt/layout/box.h
index e90a9f1..67056ab 100644
--- a/src/cobalt/layout/box.h
+++ b/src/cobalt/layout/box.h
@@ -699,6 +699,9 @@
// Updates used values of "padding" properties.
void UpdatePaddings(const LayoutParams& layout_params);
+ // Computes the rounded corners (if there are any) from the border radii.
+ base::optional<render_tree::RoundedCorners> ComputeRoundedCorners();
+
// Called after TryPlaceEllipsisOrProcessPlacedEllipsis() determines that the
// box is impacted by the ellipsis. This handles both determining the location
// of the ellipsis, if it has not already been placed, and updating the
diff --git a/src/cobalt/layout/used_style.cc b/src/cobalt/layout/used_style.cc
index 2191cc9..323425d 100644
--- a/src/cobalt/layout/used_style.cc
+++ b/src/cobalt/layout/used_style.cc
@@ -1212,15 +1212,19 @@
void UsedBorderRadiusProvider::VisitLength(cssom::LengthValue* length) {
if (length->value() > 0) {
- rounded_corners_.emplace(length->value(), length->value());
+ rounded_corner_.emplace(length->value(), length->value());
+ } else {
+ rounded_corner_ = base::nullopt;
}
}
void UsedBorderRadiusProvider::VisitPercentage(
cssom::PercentageValue* percentage) {
if (percentage->value() > 0) {
- rounded_corners_.emplace(percentage->value() * frame_size_.width(),
- percentage->value() * frame_size_.height());
+ rounded_corner_.emplace(percentage->value() * frame_size_.width(),
+ percentage->value() * frame_size_.height());
+ } else {
+ rounded_corner_ = base::nullopt;
}
}
diff --git a/src/cobalt/layout/used_style.h b/src/cobalt/layout/used_style.h
index f2ec746..2f90762 100644
--- a/src/cobalt/layout/used_style.h
+++ b/src/cobalt/layout/used_style.h
@@ -269,12 +269,12 @@
void VisitLength(cssom::LengthValue* length) OVERRIDE;
void VisitPercentage(cssom::PercentageValue* percentage) OVERRIDE;
- const base::optional<render_tree::RoundedCorners>& rounded_corners() const {
- return rounded_corners_;
+ const base::optional<render_tree::RoundedCorner>& rounded_corner() const {
+ return rounded_corner_;
}
private:
- base::optional<render_tree::RoundedCorners> rounded_corners_;
+ base::optional<render_tree::RoundedCorner> rounded_corner_;
const math::SizeF frame_size_;
diff --git a/src/cobalt/layout_tests/layout_snapshot.cc b/src/cobalt/layout_tests/layout_snapshot.cc
index de1f5ec..1fe1c7e 100644
--- a/src/cobalt/layout_tests/layout_snapshot.cc
+++ b/src/cobalt/layout_tests/layout_snapshot.cc
@@ -61,7 +61,7 @@
network::NetworkModule::Options net_options;
// Some layout tests test Content Security Policy; allow HTTP so we
// don't interfere.
- net_options.require_https = false;
+ net_options.https_requirement = network::kHTTPSOptional;
network::NetworkModule network_module(net_options);
// We do not support a media module in this mode.
@@ -86,7 +86,7 @@
base::Bind(&WebModuleOnRenderTreeProducedCallback, &results, &run_loop,
MessageLoop::current()),
base::Bind(&WebModuleErrorCallback, &run_loop, MessageLoop::current()),
- base::Closure() /* window_close_callback */,
+ browser::WebModule::CloseCallback() /* window_close_callback */,
base::Closure() /* window_minimize_callback */, stub_media_module.get(),
&network_module, viewport_size, 1.f, resource_provider, 60.0f,
web_module_options);
diff --git a/src/cobalt/layout_tests/layout_tests.cc b/src/cobalt/layout_tests/layout_tests.cc
index f377d78..55d0ea7 100644
--- a/src/cobalt/layout_tests/layout_tests.cc
+++ b/src/cobalt/layout_tests/layout_tests.cc
@@ -94,7 +94,6 @@
bool results =
pixel_tester.TestTree(animated_tree, GetParam().base_file_path);
- EXPECT_TRUE(results);
if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kRebaseline) ||
(!results &&
@@ -102,6 +101,8 @@
switches::kRebaselineFailedTests))) {
pixel_tester.Rebaseline(animated_tree, GetParam().base_file_path);
}
+
+ EXPECT_TRUE(results);
}
// Cobalt-specific test cases.
diff --git a/src/cobalt/layout_tests/testdata/css3-background/5-0-border-radius-2-values-with-background-color-and-inset-shadow.html b/src/cobalt/layout_tests/testdata/css3-background/5-0-border-radius-2-values-with-background-color-and-inset-shadow.html
new file mode 100644
index 0000000..fff02ae
--- /dev/null
+++ b/src/cobalt/layout_tests/testdata/css3-background/5-0-border-radius-2-values-with-background-color-and-inset-shadow.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<!--
+ | Setting 2 values for the border radius for a box with a background color
+ | and an inset shadow.
+ | Note that this will not look the exact same in Chrome since Cobalt
+ | normalizes opposing corners and Chrome does not.
+ | https://www.w3.org/TR/css3-background/#border-radius
+ -->
+<html>
+<head>
+ <style>
+ div {
+ background-color: rgb(176,176,176);
+ border-radius: 25px 100px;
+ box-shadow: 10px 10px #FF7F50 inset;
+ height: 200px;
+ width: 100px;
+ }
+ </style>
+</head>
+<body>
+ <div></div>
+</body>
+</html>
diff --git a/src/cobalt/layout_tests/testdata/css3-background/5-0-border-radius-2-values-with-background-color-and-outset-shadow.html b/src/cobalt/layout_tests/testdata/css3-background/5-0-border-radius-2-values-with-background-color-and-outset-shadow.html
new file mode 100644
index 0000000..ed2dc0e
--- /dev/null
+++ b/src/cobalt/layout_tests/testdata/css3-background/5-0-border-radius-2-values-with-background-color-and-outset-shadow.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<!--
+ | Setting 2 values for the border radius for a box with a background color
+ | and an outset shadow.
+ | Note that this will not look the exact same in Chrome since Cobalt
+ | normalizes opposing corners and Chrome does not.
+ | https://www.w3.org/TR/css3-background/#border-radius
+ -->
+<html>
+<head>
+ <style>
+ div {
+ background-color: rgb(176,176,176);
+ border-radius: 25px 100px;
+ box-shadow: 10px 10px #FF7F50;
+ height: 200px;
+ width: 100px;
+ }
+ </style>
+</head>
+<body>
+ <div></div>
+</body>
+</html>
diff --git a/src/cobalt/layout_tests/testdata/css3-background/5-0-border-radius-2-values-with-background-color-expected.png b/src/cobalt/layout_tests/testdata/css3-background/5-0-border-radius-2-values-with-background-color-expected.png
new file mode 100644
index 0000000..6f420eb
--- /dev/null
+++ b/src/cobalt/layout_tests/testdata/css3-background/5-0-border-radius-2-values-with-background-color-expected.png
Binary files differ
diff --git a/src/cobalt/layout_tests/testdata/css3-background/5-0-border-radius-2-values-with-background-color.html b/src/cobalt/layout_tests/testdata/css3-background/5-0-border-radius-2-values-with-background-color.html
new file mode 100644
index 0000000..9dc4581
--- /dev/null
+++ b/src/cobalt/layout_tests/testdata/css3-background/5-0-border-radius-2-values-with-background-color.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<!--
+ | Setting 2 values for the border radius for a box with a background color.
+ | Note that this will not look the exact same in Chrome since Cobalt
+ | normalizes opposing corners and Chrome does not.
+ | https://www.w3.org/TR/css3-background/#border-radius
+ -->
+<html>
+<head>
+ <style>
+ div {
+ background-color: rgb(176,176,176);
+ border-radius: 25px 100px;
+ height: 200px;
+ width: 100px;
+ }
+ </style>
+</head>
+<body>
+ <div></div>
+</body>
+</html>
\ No newline at end of file
diff --git a/src/cobalt/layout_tests/testdata/css3-background/5-0-border-radius-2-values-with-border-only-expected.png b/src/cobalt/layout_tests/testdata/css3-background/5-0-border-radius-2-values-with-border-only-expected.png
new file mode 100644
index 0000000..6bcf3b9
--- /dev/null
+++ b/src/cobalt/layout_tests/testdata/css3-background/5-0-border-radius-2-values-with-border-only-expected.png
Binary files differ
diff --git a/src/cobalt/layout_tests/testdata/css3-background/5-0-border-radius-2-values-with-border-only.html b/src/cobalt/layout_tests/testdata/css3-background/5-0-border-radius-2-values-with-border-only.html
new file mode 100644
index 0000000..0b16b13
--- /dev/null
+++ b/src/cobalt/layout_tests/testdata/css3-background/5-0-border-radius-2-values-with-border-only.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<!--
+ | Setting 2 values for the border radius for a box with a border.
+ | Note that this will not look the exact same in Chrome since Cobalt
+ | normalizes opposing corners and Chrome does not.
+ | https://www.w3.org/TR/css3-background/#border-radius
+ -->
+<html>
+<head>
+ <style>
+ div {
+ border: 25px #6495ED solid;
+ border-radius: 50px 100px;
+ height: 200px;
+ width: 100px;
+ }
+ </style>
+</head>
+<body>
+ <div></div>
+</body>
+</html>
\ No newline at end of file
diff --git a/src/cobalt/layout_tests/testdata/css3-background/5-0-border-radius-3-values-with-background-color-and-inset-shadow.html b/src/cobalt/layout_tests/testdata/css3-background/5-0-border-radius-3-values-with-background-color-and-inset-shadow.html
new file mode 100644
index 0000000..d453c0f
--- /dev/null
+++ b/src/cobalt/layout_tests/testdata/css3-background/5-0-border-radius-3-values-with-background-color-and-inset-shadow.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<!--
+ | Setting 3 values for the border radius for a box with a background color
+ | and an inset shadow.
+ | Note that this will not look the exact same in Chrome since Cobalt
+ | normalizes opposing corners and Chrome does not.
+ | https://www.w3.org/TR/css3-background/#border-radius
+ -->
+<html>
+<head>
+ <style>
+ div {
+ background-color: rgb(176,176,176);
+ border-radius: 10px 120px 50px;
+ box-shadow: 10px 10px #FF7F50 inset;
+ height: 200px;
+ width: 100px;
+ }
+ </style>
+</head>
+<body>
+ <div></div>
+</body>
+</html>
\ No newline at end of file
diff --git a/src/cobalt/layout_tests/testdata/css3-background/5-0-border-radius-3-values-with-background-color-and-outset-shadow.html b/src/cobalt/layout_tests/testdata/css3-background/5-0-border-radius-3-values-with-background-color-and-outset-shadow.html
new file mode 100644
index 0000000..dac58e5
--- /dev/null
+++ b/src/cobalt/layout_tests/testdata/css3-background/5-0-border-radius-3-values-with-background-color-and-outset-shadow.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<!--
+ | Setting 3 values for the border radius for a box with a background color
+ | and an outset shadow.
+ | Note that this will not look the exact same in Chrome since Cobalt
+ | normalizes opposing corners and Chrome does not.
+ | https://www.w3.org/TR/css3-background/#border-radius
+ -->
+<html>
+<head>
+ <style>
+ div {
+ background-color: rgb(176,176,176);
+ border-radius: 10px 120px 50px;
+ box-shadow: 10px 10px #FF7F50;
+ height: 200px;
+ width: 100px;
+ }
+ </style>
+</head>
+<body>
+ <div></div>
+</body>
+</html>
\ No newline at end of file
diff --git a/src/cobalt/layout_tests/testdata/css3-background/5-0-border-radius-3-values-with-background-color-expected.png b/src/cobalt/layout_tests/testdata/css3-background/5-0-border-radius-3-values-with-background-color-expected.png
new file mode 100644
index 0000000..5e019e4
--- /dev/null
+++ b/src/cobalt/layout_tests/testdata/css3-background/5-0-border-radius-3-values-with-background-color-expected.png
Binary files differ
diff --git a/src/cobalt/layout_tests/testdata/css3-background/5-0-border-radius-3-values-with-background-color.html b/src/cobalt/layout_tests/testdata/css3-background/5-0-border-radius-3-values-with-background-color.html
new file mode 100644
index 0000000..47866c0
--- /dev/null
+++ b/src/cobalt/layout_tests/testdata/css3-background/5-0-border-radius-3-values-with-background-color.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<!--
+ | Setting 3 values for the border radius for a box with a background color.
+ | Note that this will not look the exact same in Chrome since Cobalt
+ | normalizes opposing corners and Chrome does not.
+ | https://www.w3.org/TR/css3-background/#border-radius
+ -->
+<html>
+<head>
+ <style>
+ div {
+ background-color: rgb(176,176,176);
+ border-radius: 10px 120px 50px;
+ height: 200px;
+ width: 100px;
+ }
+ </style>
+</head>
+<body>
+ <div></div>
+</body>
+</html>
\ No newline at end of file
diff --git a/src/cobalt/layout_tests/testdata/css3-background/5-0-border-radius-3-values-with-border-only-expected.png b/src/cobalt/layout_tests/testdata/css3-background/5-0-border-radius-3-values-with-border-only-expected.png
new file mode 100644
index 0000000..8b5f44d
--- /dev/null
+++ b/src/cobalt/layout_tests/testdata/css3-background/5-0-border-radius-3-values-with-border-only-expected.png
Binary files differ
diff --git a/src/cobalt/layout_tests/testdata/css3-background/5-0-border-radius-3-values-with-border-only.html b/src/cobalt/layout_tests/testdata/css3-background/5-0-border-radius-3-values-with-border-only.html
new file mode 100644
index 0000000..56de16a
--- /dev/null
+++ b/src/cobalt/layout_tests/testdata/css3-background/5-0-border-radius-3-values-with-border-only.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<!--
+ | Setting 3 values for the border radius for a box with a border.
+ | Note that this will not look the exact same in Chrome since Cobalt
+ | normalizes opposing corners and Chrome does not.
+ | https://www.w3.org/TR/css3-background/#border-radius
+ -->
+<html>
+<head>
+ <style>
+ div {
+ border: 25px #6495ED solid;
+ border-radius: 10px 120px 50px;
+ height: 200px;
+ width: 100px;
+ }
+ </style>
+</head>
+<body>
+ <div></div>
+</body>
+</html>
\ No newline at end of file
diff --git a/src/cobalt/layout_tests/testdata/css3-background/5-0-border-radius-4-values-with-background-color-and-inset-shadow.html b/src/cobalt/layout_tests/testdata/css3-background/5-0-border-radius-4-values-with-background-color-and-inset-shadow.html
new file mode 100644
index 0000000..c443b15
--- /dev/null
+++ b/src/cobalt/layout_tests/testdata/css3-background/5-0-border-radius-4-values-with-background-color-and-inset-shadow.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<!--
+ | Setting 4 values for the border radius for a box with a background color
+ | and an inset shadow.
+ | Note that this will not look the exact same in Chrome since Cobalt
+ | normalizes opposing corners and Chrome does not.
+ | https://www.w3.org/TR/css3-background/#border-radius
+ -->
+<html>
+<head>
+ <style>
+ div {
+ background-color: rgb(176,176,176);
+ border-radius: 10px 120px 20px 70px;
+ box-shadow: 10px 10px #FF7F50 inset;
+ height: 200px;
+ width: 100px;
+ }
+ </style>
+</head>
+<body>
+ <div></div>
+</body>
+</html>
\ No newline at end of file
diff --git a/src/cobalt/layout_tests/testdata/css3-background/5-0-border-radius-4-values-with-background-color-and-outset-shadow.html b/src/cobalt/layout_tests/testdata/css3-background/5-0-border-radius-4-values-with-background-color-and-outset-shadow.html
new file mode 100644
index 0000000..c9bfeb8
--- /dev/null
+++ b/src/cobalt/layout_tests/testdata/css3-background/5-0-border-radius-4-values-with-background-color-and-outset-shadow.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<!--
+ | Setting 4 values for the border radius for a box with a background color
+ | and an outset shadow.
+ | Note that this will not look the exact same in Chrome since Cobalt
+ | normalizes opposing corners and Chrome does not.
+ | https://www.w3.org/TR/css3-background/#border-radius
+ -->
+<html>
+<head>
+ <style>
+ div {
+ background-color: rgb(176,176,176);
+ border-radius: 10px 120px 20px 70px;
+ box-shadow: 10px 10px #FF7F50;
+ height: 200px;
+ width: 100px;
+ }
+ </style>
+</head>
+<body>
+ <div></div>
+</body>
+</html>
\ No newline at end of file
diff --git a/src/cobalt/layout_tests/testdata/css3-background/5-0-border-radius-4-values-with-background-color-expected.png b/src/cobalt/layout_tests/testdata/css3-background/5-0-border-radius-4-values-with-background-color-expected.png
new file mode 100644
index 0000000..d424893
--- /dev/null
+++ b/src/cobalt/layout_tests/testdata/css3-background/5-0-border-radius-4-values-with-background-color-expected.png
Binary files differ
diff --git a/src/cobalt/layout_tests/testdata/css3-background/5-0-border-radius-4-values-with-background-color.html b/src/cobalt/layout_tests/testdata/css3-background/5-0-border-radius-4-values-with-background-color.html
new file mode 100644
index 0000000..035a589
--- /dev/null
+++ b/src/cobalt/layout_tests/testdata/css3-background/5-0-border-radius-4-values-with-background-color.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<!--
+ | Setting 4 values for the border radius for a box with a background color.
+ | Note that this will not look the exact same in Chrome since Cobalt
+ | normalizes opposing corners and Chrome does not.
+ | https://www.w3.org/TR/css3-background/#border-radius
+ -->
+<html>
+<head>
+ <style>
+ div {
+ background-color: rgb(176,176,176);
+ border-radius: 10px 120px 20px 70px;
+ height: 200px;
+ width: 100px;
+ }
+ </style>
+</head>
+<body>
+ <div></div>
+</body>
+</html>
\ No newline at end of file
diff --git a/src/cobalt/layout_tests/testdata/css3-background/5-0-border-radius-4-values-with-border-only-expected.png b/src/cobalt/layout_tests/testdata/css3-background/5-0-border-radius-4-values-with-border-only-expected.png
new file mode 100644
index 0000000..296cc7d
--- /dev/null
+++ b/src/cobalt/layout_tests/testdata/css3-background/5-0-border-radius-4-values-with-border-only-expected.png
Binary files differ
diff --git a/src/cobalt/layout_tests/testdata/css3-background/5-0-border-radius-4-values-with-border-only.html b/src/cobalt/layout_tests/testdata/css3-background/5-0-border-radius-4-values-with-border-only.html
new file mode 100644
index 0000000..5cf86bb
--- /dev/null
+++ b/src/cobalt/layout_tests/testdata/css3-background/5-0-border-radius-4-values-with-border-only.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<!--
+ | Setting 4 values for the border radius for a box with a border.
+ | Note that this will not look the exact same in Chrome since Cobalt
+ | normalizes opposing corners and Chrome does not.
+ | https://www.w3.org/TR/css3-background/#border-radius
+ -->
+<html>
+<head>
+ <style>
+ div {
+ border: 25px #6495ED solid;
+ border-radius: 50px 120px 40px 70px;
+ height: 200px;
+ width: 100px;
+ }
+ </style>
+</head>
+<body>
+ <div></div>
+</body>
+</html>
\ No newline at end of file
diff --git a/src/cobalt/layout_tests/testdata/css3-background/5-0-border-radius-with-zero-value-and-background-color-and-inset-shadow.html b/src/cobalt/layout_tests/testdata/css3-background/5-0-border-radius-with-zero-value-and-background-color-and-inset-shadow.html
new file mode 100644
index 0000000..30a32f8
--- /dev/null
+++ b/src/cobalt/layout_tests/testdata/css3-background/5-0-border-radius-with-zero-value-and-background-color-and-inset-shadow.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<!--
+ | Setting 4 values for the border radius for a box with a background color
+ | and an inset shadow.
+ | Note that this will not look the exact same in Chrome since Cobalt
+ | normalizes opposing corners and Chrome does not.
+ | https://www.w3.org/TR/css3-background/#border-radius
+ -->
+<html>
+<head>
+ <style>
+ div {
+ background-color: rgb(176,176,176);
+ border-radius: 10px 120px 0px 70px;
+ box-shadow: 10px 10px #FF7F50 inset;
+ height: 200px;
+ width: 100px;
+ }
+ </style>
+</head>
+<body>
+ <div></div>
+</body>
+</html>
\ No newline at end of file
diff --git a/src/cobalt/layout_tests/testdata/css3-background/5-0-border-radius-with-zero-value-and-background-color-and-outset-shadow.html b/src/cobalt/layout_tests/testdata/css3-background/5-0-border-radius-with-zero-value-and-background-color-and-outset-shadow.html
new file mode 100644
index 0000000..9f4781d
--- /dev/null
+++ b/src/cobalt/layout_tests/testdata/css3-background/5-0-border-radius-with-zero-value-and-background-color-and-outset-shadow.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<!--
+ | Setting 4 values for the border radius for a box with a background color
+ | and an outset shadow.
+ | Note that this will not look the exact same in Chrome since Cobalt
+ | normalizes opposing corners and Chrome does not.
+ | https://www.w3.org/TR/css3-background/#border-radius
+ -->
+<html>
+<head>
+ <style>
+ div {
+ background-color: rgb(176,176,176);
+ border-radius: 10px 120px 0px 70px;
+ box-shadow: 10px 10px #FF7F50;
+ height: 200px;
+ width: 100px;
+ }
+ </style>
+</head>
+<body>
+ <div></div>
+</body>
+</html>
\ No newline at end of file
diff --git a/src/cobalt/layout_tests/testdata/css3-background/5-0-border-radius-with-zero-value-and-background-color-expected.png b/src/cobalt/layout_tests/testdata/css3-background/5-0-border-radius-with-zero-value-and-background-color-expected.png
new file mode 100644
index 0000000..a9c2039
--- /dev/null
+++ b/src/cobalt/layout_tests/testdata/css3-background/5-0-border-radius-with-zero-value-and-background-color-expected.png
Binary files differ
diff --git a/src/cobalt/layout_tests/testdata/css3-background/5-0-border-radius-with-zero-value-and-background-color.html b/src/cobalt/layout_tests/testdata/css3-background/5-0-border-radius-with-zero-value-and-background-color.html
new file mode 100644
index 0000000..6a23bd8
--- /dev/null
+++ b/src/cobalt/layout_tests/testdata/css3-background/5-0-border-radius-with-zero-value-and-background-color.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<!--
+ | Setting 4 values for the border radius for a box with a background color.
+ | Note that this will not look the exact same in Chrome since Cobalt
+ | normalizes opposing corners and Chrome does not.
+ | https://www.w3.org/TR/css3-background/#border-radius
+ -->
+<html>
+<head>
+ <style>
+ div {
+ background-color: rgb(176,176,176);
+ border-radius: 25px 100px 0px 75px;
+ height: 200px;
+ width: 100px;
+ }
+ </style>
+</head>
+<body>
+ <div></div>
+</body>
+</html>
+
diff --git a/src/cobalt/layout_tests/testdata/css3-background/5-0-border-radius-with-zero-value-and-border-only-expected.png b/src/cobalt/layout_tests/testdata/css3-background/5-0-border-radius-with-zero-value-and-border-only-expected.png
new file mode 100644
index 0000000..f0eb38f
--- /dev/null
+++ b/src/cobalt/layout_tests/testdata/css3-background/5-0-border-radius-with-zero-value-and-border-only-expected.png
Binary files differ
diff --git a/src/cobalt/layout_tests/testdata/css3-background/5-0-border-radius-with-zero-value-and-border-only.html b/src/cobalt/layout_tests/testdata/css3-background/5-0-border-radius-with-zero-value-and-border-only.html
new file mode 100644
index 0000000..5cfffb1
--- /dev/null
+++ b/src/cobalt/layout_tests/testdata/css3-background/5-0-border-radius-with-zero-value-and-border-only.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<!--
+ | Setting 4 values for the border radius for a box with a border.
+ | Note that this will not look the exact same in Chrome since Cobalt
+ | normalizes opposing corners and Chrome does not.
+ | https://www.w3.org/TR/css3-background/#border-radius
+ -->
+<html>
+<head>
+ <style>
+ div {
+ border: 25px #6495ED solid;
+ border-radius: 40px 100px 0px 75px;
+ height: 200px;
+ width: 100px;
+ }
+ </style>
+</head>
+<body>
+ <div></div>
+</body>
+</html>
+
diff --git a/src/cobalt/layout_tests/testdata/css3-background/layout_tests.txt b/src/cobalt/layout_tests/testdata/css3-background/layout_tests.txt
index 2c12a56..03230b9 100644
--- a/src/cobalt/layout_tests/testdata/css3-background/layout_tests.txt
+++ b/src/cobalt/layout_tests/testdata/css3-background/layout_tests.txt
@@ -73,6 +73,12 @@
4-0-border-width-with-solid-border-style
4-0-different-border-styles-with-different-border-widths
4-0-different-border-widths-with-solid-border-style
+5-0-border-radius-2-values-with-background-color
+5-0-border-radius-2-values-with-border-only
+5-0-border-radius-3-values-with-background-color
+5-0-border-radius-3-values-with-border-only
+5-0-border-radius-4-values-with-background-color
+5-0-border-radius-4-values-with-border-only
5-0-border-radius-circle-with-background-color-and-border
5-0-border-radius-circle-with-background-image-and-border
5-0-border-radius-with-background-color
@@ -80,6 +86,8 @@
5-0-border-radius-with-background-image
5-0-border-radius-with-background-image-and-border
5-0-border-radius-with-border-only
+5-0-border-radius-with-zero-value-and-background-color
+5-0-border-radius-with-zero-value-and-border-only
7-1-1-box-shadow-with-inset
7-1-1-box-shadow-with-inset-and-blur-and-spread
7-1-1-box-shadow-with-spread
diff --git a/src/cobalt/layout_tests/web_platform_test_parser.cc b/src/cobalt/layout_tests/web_platform_test_parser.cc
index 50b6c1e..04f894e 100644
--- a/src/cobalt/layout_tests/web_platform_test_parser.cc
+++ b/src/cobalt/layout_tests/web_platform_test_parser.cc
@@ -101,8 +101,7 @@
// Evaluate the javascript precondition. Enumerate the web platform tests
// only if the precondition is true.
scoped_ptr<script::JavaScriptEngine> engine =
- script::JavaScriptEngine::CreateEngine(
- script::JavaScriptEngine::Options());
+ script::JavaScriptEngine::CreateEngine();
scoped_refptr<script::GlobalEnvironment> global_environment =
engine->CreateGlobalEnvironment();
global_environment->CreateGlobalObject();
diff --git a/src/cobalt/layout_tests/web_platform_tests.cc b/src/cobalt/layout_tests/web_platform_tests.cc
index 01788fd..ed6e5c4 100644
--- a/src/cobalt/layout_tests/web_platform_tests.cc
+++ b/src/cobalt/layout_tests/web_platform_tests.cc
@@ -46,22 +46,23 @@
public:
CspDelegatePermissive(
scoped_ptr<dom::CspViolationReporter> violation_reporter, const GURL& url,
- const std::string& location_policy,
+ const std::string& location_policy, csp::CSPHeaderPolicy require_csp,
const base::Closure& policy_changed_callback)
: dom::CspDelegateSecure(violation_reporter.Pass(), url, location_policy,
- policy_changed_callback) {
+ require_csp, policy_changed_callback) {
// Lies, but some checks in our parent require this.
was_header_received_ = true;
}
static CspDelegate* Create(
scoped_ptr<dom::CspViolationReporter> violation_reporter, const GURL& url,
- const std::string& location_policy,
+ const std::string& location_policy, csp::CSPHeaderPolicy require_csp,
const base::Closure& policy_changed_callback,
int insecure_allowed_token) {
UNREFERENCED_PARAMETER(insecure_allowed_token);
return new CspDelegatePermissive(violation_reporter.Pass(), url,
- location_policy, policy_changed_callback);
+ location_policy, require_csp,
+ policy_changed_callback);
}
bool OnReceiveHeaders(const csp::ResponseHeaders& headers) OVERRIDE {
@@ -150,7 +151,7 @@
// Network module
network::NetworkModule::Options net_options;
- net_options.require_https = false;
+ net_options.https_requirement = network::kHTTPSOptional;
network::NetworkModule network_module(net_options);
// Media module
@@ -177,7 +178,7 @@
base::Bind(&WebModuleOnRenderTreeProducedCallback, &results, &run_loop,
MessageLoop::current()),
base::Bind(&WebModuleErrorCallback, &run_loop, MessageLoop::current()),
- base::Closure() /* window_close_callback */,
+ browser::WebModule::CloseCallback() /* window_close_callback */,
base::Closure() /* window_minimize_callback */, media_module.get(),
&network_module, kDefaultViewportSize, 1.f, &resource_provider, 60.0f,
web_module_options);
diff --git a/src/cobalt/loader/loader.gyp b/src/cobalt/loader/loader.gyp
index cf037bf..2b3ecf1 100644
--- a/src/cobalt/loader/loader.gyp
+++ b/src/cobalt/loader/loader.gyp
@@ -184,8 +184,8 @@
'<(input_directory)/cobalt_splash_screen.css',
'<(input_directory)/cobalt_splash_screen.html',
'<(input_directory)/equirectangular_40_40.msh',
- '<(input_directory)/youtube_splash_screen.html',
'<(input_directory)/splash_screen.js',
+ '<!@(["python", "<(DEPTH)/starboard/tools/find_private_files.py", "<(DEPTH)", "*.html", "cobalt/loader/embedded_resources"])',
],
'actions': [
{
diff --git a/src/cobalt/loader/resource_cache.h b/src/cobalt/loader/resource_cache.h
index 336d137..024cc55 100644
--- a/src/cobalt/loader/resource_cache.h
+++ b/src/cobalt/loader/resource_cache.h
@@ -510,10 +510,14 @@
base::ThreadChecker resource_cache_thread_checker_;
- base::CVal<base::cval::SizeInBytes, base::CValPublic> size_in_bytes_;
- base::CVal<base::cval::SizeInBytes, base::CValPublic> capacity_in_bytes_;
- base::CVal<int> count_requested_resources_;
- base::CVal<int> count_loading_resources_;
+ base::CVal<base::cval::SizeInBytes, base::CValPublic> memory_size_in_bytes_;
+ base::CVal<base::cval::SizeInBytes, base::CValPublic>
+ memory_capacity_in_bytes_;
+ base::CVal<base::cval::SizeInBytes> memory_resources_loaded_in_bytes_;
+
+ base::CVal<int> count_resources_requested_;
+ base::CVal<int> count_resources_loading_;
+ base::CVal<int> count_resources_loaded_;
base::CVal<int> count_pending_callbacks_;
DISALLOW_COPY_AND_ASSIGN(ResourceCache);
@@ -532,20 +536,28 @@
create_loader_function_(create_loader_function),
is_processing_pending_callbacks_(false),
are_callbacks_disabled_(false),
- size_in_bytes_(base::StringPrintf("Memory.%s.Size", name_.c_str()), 0,
- "Total number of bytes currently used by the cache."),
- capacity_in_bytes_(
+ memory_size_in_bytes_(
+ base::StringPrintf("Memory.%s.Size", name_.c_str()), 0,
+ "Total number of bytes currently used by the cache."),
+ memory_capacity_in_bytes_(
base::StringPrintf("Memory.%s.Capacity", name_.c_str()),
cache_capacity_,
"The capacity, in bytes, of the resource cache. "
"Exceeding this results in *unused* resources being "
"purged."),
- count_requested_resources_(
- base::StringPrintf("Count.%s.RequestedResources", name_.c_str()), 0,
+ memory_resources_loaded_in_bytes_(
+ base::StringPrintf("Memory.%s.Resource.Loaded", name_.c_str()), 0,
+ "Combined size in bytes of all resources that have been loaded by "
+ "the cache."),
+ count_resources_requested_(
+ base::StringPrintf("Count.%s.Resource.Requested", name_.c_str()), 0,
"The total number of resources that have been requested."),
- count_loading_resources_(
- base::StringPrintf("Count.%s.LoadingResources", name_.c_str()), 0,
- "The number of loading resources that are still outstanding."),
+ count_resources_loading_(
+ base::StringPrintf("Count.%s.Resource.Loading", name_.c_str()), 0,
+ "The number of resources that are currently loading."),
+ count_resources_loaded_(
+ base::StringPrintf("Count.%s.Resource.Loaded", name_.c_str()), 0,
+ "The total number of resources that have been successfully loaded."),
count_pending_callbacks_(
base::StringPrintf("Count.%s.PendingCallbacks", name_.c_str()), 0,
"The number of loading completed resources that have pending "
@@ -580,7 +592,7 @@
}
// If we reach this point, then the resource doesn't exist yet.
- ++count_requested_resources_;
+ ++count_resources_requested_;
// Add the resource to a loading set. If no current resources have pending
// callbacks, then this resource will block callbacks until it is decoded.
@@ -593,7 +605,7 @@
} else {
non_callback_blocking_loading_resource_set_.insert(url.spec());
}
- ++count_loading_resources_;
+ ++count_resources_loading_;
// Create the cached resource and fetch its resource based on the url.
scoped_refptr<CachedResourceType> cached_resource(new CachedResourceType(
@@ -613,7 +625,7 @@
void ResourceCache<CacheType>::SetCapacity(uint32 capacity) {
DCHECK(resource_cache_thread_checker_.CalledOnValidThread());
cache_capacity_ = capacity;
- capacity_in_bytes_ = capacity;
+ memory_capacity_in_bytes_ = capacity;
ReclaimMemoryAndMaybeProcessPendingCallbacks(cache_capacity_);
}
@@ -637,8 +649,12 @@
const std::string& url = cached_resource->url().spec();
if (cached_resource->TryGetResource()) {
- size_in_bytes_ +=
+ uint32 estimated_size_in_bytes =
CacheType::GetEstimatedSizeInBytes(cached_resource->TryGetResource());
+ memory_size_in_bytes_ += estimated_size_in_bytes;
+ memory_resources_loaded_in_bytes_ += estimated_size_in_bytes;
+
+ ++count_resources_loaded_;
}
// Remove the resource from its loading set. It should exist in exactly one
@@ -659,7 +675,7 @@
// incremented first to ensure that the total of the two counts always remains
// above 0.
++count_pending_callbacks_;
- --count_loading_resources_;
+ --count_resources_loading_;
ProcessPendingCallbacksIfUnblocked();
ReclaimMemoryAndMaybeProcessPendingCallbacks(cache_capacity_);
@@ -690,10 +706,10 @@
DCHECK(non_callback_blocking_loading_resource_set_.find(url) ==
non_callback_blocking_loading_resource_set_.end());
DCHECK(pending_callback_map_.find(url) == pending_callback_map_.end());
- --count_loading_resources_;
+ --count_resources_loading_;
} else if (non_callback_blocking_loading_resource_set_.erase(url)) {
DCHECK(pending_callback_map_.find(url) == pending_callback_map_.end());
- --count_loading_resources_;
+ --count_resources_loading_;
} else if (pending_callback_map_.erase(url)) {
--count_pending_callbacks_;
}
@@ -717,7 +733,7 @@
// pending callbacks and try again. References to the cached resources are
// potentially being held until the callbacks run, so processing them may
// enable more memory to be reclaimed.
- if (size_in_bytes_ > bytes_to_reclaim_down_to) {
+ if (memory_size_in_bytes_ > bytes_to_reclaim_down_to) {
ProcessPendingCallbacks();
ReclaimMemory(bytes_to_reclaim_down_to, true /*log_warning_if_over*/);
}
@@ -728,7 +744,7 @@
bool log_warning_if_over) {
DCHECK(resource_cache_thread_checker_.CalledOnValidThread());
- while (size_in_bytes_ > bytes_to_reclaim_down_to &&
+ while (memory_size_in_bytes_ > bytes_to_reclaim_down_to &&
!unreference_cached_resource_map_.empty()) {
// The first element is the earliest-inserted element.
scoped_refptr<ResourceType> resource =
@@ -739,15 +755,15 @@
// in linked_hash_map. Add that function and related unit test.
unreference_cached_resource_map_.erase(
unreference_cached_resource_map_.begin());
- size_in_bytes_ -= first_resource_size;
+ memory_size_in_bytes_ -= first_resource_size;
}
if (log_warning_if_over) {
// Log a warning if we're still over |bytes_to_reclaim_down_to| after
// attempting to reclaim memory. This can occur validly when the size of
// the referenced images exceeds the target size.
- DLOG_IF(WARNING, size_in_bytes_ > bytes_to_reclaim_down_to)
- << "cached size: " << size_in_bytes_
+ DLOG_IF(WARNING, memory_size_in_bytes_ > bytes_to_reclaim_down_to)
+ << "cached size: " << memory_size_in_bytes_
<< ", target size: " << bytes_to_reclaim_down_to;
}
}
diff --git a/src/cobalt/media/sandbox/media_sandbox.cc b/src/cobalt/media/sandbox/media_sandbox.cc
index 19345f9..59edcc0 100644
--- a/src/cobalt/media/sandbox/media_sandbox.cc
+++ b/src/cobalt/media/sandbox/media_sandbox.cc
@@ -72,7 +72,7 @@
const FilePath& trace_log_path) {
trace_to_file_.reset(new trace_event::ScopedTraceToFile(trace_log_path));
network::NetworkModule::Options network_options;
- network_options.require_https = false;
+ network_options.https_requirement = network::kHTTPSOptional;
network_module_.reset(new network::NetworkModule(network_options));
fetcher_factory_.reset(new loader::FetcherFactory(network_module_.get()));
diff --git a/src/cobalt/network/network_delegate.cc b/src/cobalt/network/network_delegate.cc
index 2755569..4ebee31 100644
--- a/src/cobalt/network/network_delegate.cc
+++ b/src/cobalt/network/network_delegate.cc
@@ -23,10 +23,10 @@
namespace network {
NetworkDelegate::NetworkDelegate(net::StaticCookiePolicy::Type cookie_policy,
- bool require_https)
+ network::HTTPSRequirement https_requirement)
: cookie_policy_(cookie_policy),
cookies_enabled_(true),
- require_https_(require_https) {}
+ https_requirement_(https_requirement) {}
NetworkDelegate::~NetworkDelegate() {}
@@ -37,16 +37,13 @@
UNREFERENCED_PARAMETER(callback);
UNREFERENCED_PARAMETER(new_url);
-#if defined(COBALT_FORCE_HTTPS)
- const bool require_https = true;
-#else
- bool require_https = require_https_;
-#endif
-
const GURL& url = request->url();
- if (!require_https) {
+ if (url.SchemeIsSecure() || url.SchemeIs("data")) {
return net::OK;
- } else if (url.SchemeIsSecure() || url.SchemeIs("data")) {
+ } else if (https_requirement_ == kHTTPSOptional) {
+ DLOG(WARNING)
+ << "Page must be served over secure scheme, it will fail to load "
+ "in production builds of Cobalt.";
return net::OK;
}
diff --git a/src/cobalt/network/network_delegate.h b/src/cobalt/network/network_delegate.h
index 344a0ea..f61049f 100644
--- a/src/cobalt/network/network_delegate.h
+++ b/src/cobalt/network/network_delegate.h
@@ -23,6 +23,13 @@
namespace cobalt {
namespace network {
+
+// Used to tell if HTTPS scheme has to be used.
+enum HTTPSRequirement {
+ kHTTPSRequired,
+ kHTTPSOptional,
+};
+
// A NetworkDelegate receives callbacks when network events occur.
// Each override can specify custom behavior or just add additional logging.
// We do nothing for most events, but our network delegate
@@ -30,7 +37,7 @@
class NetworkDelegate : public net::NetworkDelegate {
public:
NetworkDelegate(net::StaticCookiePolicy::Type cookie_policy,
- bool require_https);
+ network::HTTPSRequirement https_requirement);
~NetworkDelegate() OVERRIDE;
// For debugging, we allow blocking all cookies.
@@ -84,7 +91,7 @@
private:
net::StaticCookiePolicy::Type cookie_policy_;
bool cookies_enabled_;
- bool require_https_;
+ network::HTTPSRequirement https_requirement_;
DISALLOW_COPY_AND_ASSIGN(NetworkDelegate);
};
diff --git a/src/cobalt/network/network_module.cc b/src/cobalt/network/network_module.cc
index f9fb043..059ced9 100644
--- a/src/cobalt/network/network_module.cc
+++ b/src/cobalt/network/network_module.cc
@@ -151,7 +151,7 @@
new URLRequestContext(storage_manager_, options_.custom_proxy, net_log,
options_.ignore_certificate_errors));
network_delegate_.reset(
- new NetworkDelegate(options_.cookie_policy, options_.require_https));
+ new NetworkDelegate(options_.cookie_policy, options_.https_requirement));
url_request_context_->set_http_user_agent_settings(
http_user_agent_settings_.get());
url_request_context_->set_network_delegate(network_delegate_.get());
diff --git a/src/cobalt/network/network_module.h b/src/cobalt/network/network_module.h
index 222a05c..2b51e12 100644
--- a/src/cobalt/network/network_module.h
+++ b/src/cobalt/network/network_module.h
@@ -60,11 +60,11 @@
: cookie_policy(
net::StaticCookiePolicy::BLOCK_SETTING_THIRD_PARTY_COOKIES),
ignore_certificate_errors(false),
- require_https(true),
+ https_requirement(network::kHTTPSRequired),
preferred_language("en-US") {}
net::StaticCookiePolicy::Type cookie_policy;
bool ignore_certificate_errors;
- bool require_https;
+ HTTPSRequirement https_requirement;
std::string preferred_language;
std::string custom_proxy;
};
diff --git a/src/cobalt/renderer/pipeline.cc b/src/cobalt/renderer/pipeline.cc
index 8827ef4..4fb1ee3 100644
--- a/src/cobalt/renderer/pipeline.cc
+++ b/src/cobalt/renderer/pipeline.cc
@@ -35,11 +35,6 @@
namespace renderer {
namespace {
-// In order to put a bound on memory we set a maximum submission queue size that
-// is empirically found to be a nice balance between animation smoothing and
-// memory usage.
-const size_t kMaxSubmissionQueueSize = 4u;
-
// How quickly the renderer time adjusts to changing submission times.
// 500ms is chosen as a default because it is fast enough that the user will not
// usually notice input lag from a slow timeline renderer, but slow enough that
@@ -84,6 +79,7 @@
submit_even_if_render_tree_is_unchanged),
last_did_rasterize_(false),
last_animations_expired_(true),
+ last_stat_tracked_animations_expired_(true),
rasterize_periodic_timer_("Renderer.Rasterize.Duration",
kRasterizePeriodicTimerEntriesPerUpdate,
false /*enable_entry_list_c_val*/),
@@ -233,14 +229,40 @@
render_target_->GetSize());
}
+void Pipeline::TimeFence(base::TimeDelta time_fence) {
+ TRACK_MEMORY_SCOPE("Renderer");
+ TRACE_EVENT0("cobalt::renderer", "Pipeline::TimeFence()");
+
+ if (MessageLoop::current() != rasterizer_thread_.message_loop()) {
+ rasterizer_thread_.message_loop()->PostTask(
+ FROM_HERE,
+ base::Bind(&Pipeline::TimeFence, base::Unretained(this), time_fence));
+ return;
+ }
+
+ if (!time_fence_) {
+ time_fence_ = time_fence;
+ } else {
+ LOG(ERROR) << "Attempting to set a time fence while one was already set.";
+ }
+}
+
void Pipeline::SetNewRenderTree(const Submission& render_tree_submission) {
DCHECK(rasterizer_thread_checker_.CalledOnValidThread());
DCHECK(render_tree_submission.render_tree.get());
TRACE_EVENT0("cobalt::renderer", "Pipeline::SetNewRenderTree()");
- submission_queue_->PushSubmission(render_tree_submission,
- base::TimeTicks::Now());
+ // If a time fence is active, save the submission to be queued only after
+ // we pass the time fence. Overwrite any existing waiting submission in this
+ // case.
+ if (time_fence_) {
+ post_fence_submission_ = render_tree_submission;
+ post_fence_receipt_time_ = base::TimeTicks::Now();
+ return;
+ }
+
+ QueueSubmission(render_tree_submission, base::TimeTicks::Now());
// Start the rasterization timer if it is not yet started.
if (!rasterize_timer_) {
@@ -260,7 +282,7 @@
DCHECK(rasterizer_thread_checker_.CalledOnValidThread());
TRACE_EVENT0("cobalt::renderer", "Pipeline::ClearCurrentRenderTree()");
- submission_queue_->Reset();
+ ResetSubmissionQueue();
rasterize_timer_ = base::nullopt;
}
@@ -280,37 +302,55 @@
// If our render tree hasn't changed from the one that was previously
// rendered and it's okay on this system to not flip the display buffer
// frequently, then we can just not do anything here.
- if (!fps_overlay_update_pending_ &&
- !submit_even_if_render_tree_is_unchanged_ && !has_render_tree_changed) {
- return;
+ if (fps_overlay_update_pending_ || submit_even_if_render_tree_is_unchanged_ ||
+ has_render_tree_changed) {
+ // Check whether the animations in the render tree that is being rasterized
+ // are active.
+ render_tree::animations::AnimateNode* animate_node =
+ base::polymorphic_downcast<render_tree::animations::AnimateNode*>(
+ submission.render_tree.get());
+
+ // Rasterize the last submitted render tree.
+ bool did_rasterize =
+ RasterizeSubmissionToRenderTarget(submission, render_target_);
+
+ bool animations_expired = animate_node->expiry() <= submission.time_offset;
+ bool stat_tracked_animations_expired =
+ animate_node->depends_on_time_expiry() <= submission.time_offset;
+
+ UpdateRasterizeStats(did_rasterize, stat_tracked_animations_expired,
+ is_new_render_tree, start_rasterize_time,
+ base::TimeTicks::Now());
+
+ last_did_rasterize_ = did_rasterize;
+ last_animations_expired_ = animations_expired;
+ last_stat_tracked_animations_expired_ = stat_tracked_animations_expired;
}
- // Check whether the animations in the render tree that is being rasterized
- // are active.
- render_tree::animations::AnimateNode* animate_node =
- base::polymorphic_downcast<render_tree::animations::AnimateNode*>(
- submission.render_tree.get());
+ if (time_fence_ && submission_queue_->submission_time(
+ base::TimeTicks::Now()) >= *time_fence_) {
+ // A time fence was active and we just crossed it, so reset it.
+ time_fence_ = base::nullopt;
- // Rasterize the last submitted render tree.
- bool did_rasterize =
- RasterizeSubmissionToRenderTarget(submission, render_target_);
-
- bool animations_expired = animate_node->expiry() <= submission.time_offset;
-
- UpdateRasterizeStats(did_rasterize, animations_expired, is_new_render_tree,
- start_rasterize_time, base::TimeTicks::Now());
-
- last_did_rasterize_ = did_rasterize;
- last_animations_expired_ = animations_expired;
+ if (post_fence_submission_) {
+ // A submission was waiting to be queued once we passed the time fence,
+ // so go ahead and queue it now.
+ QueueSubmission(*post_fence_submission_, *post_fence_receipt_time_);
+ post_fence_submission_ = base::nullopt;
+ post_fence_receipt_time_ = base::nullopt;
+ }
+ }
}
-void Pipeline::UpdateRasterizeStats(bool did_rasterize, bool animations_expired,
+void Pipeline::UpdateRasterizeStats(bool did_rasterize,
+ bool are_stat_tracked_animations_expired,
bool is_new_render_tree,
base::TimeTicks start_time,
base::TimeTicks end_time) {
bool last_animations_active =
- !last_animations_expired_ && last_did_rasterize_;
- bool animations_active = !animations_expired && did_rasterize;
+ !last_stat_tracked_animations_expired_ && last_did_rasterize_;
+ bool animations_active =
+ !are_stat_tracked_animations_expired && did_rasterize;
// The rasterization is only timed with the periodic timer when the render
// tree has changed. This ensures that the frames being timed are consistent
@@ -463,11 +503,7 @@
base::Thread::Options(MessageLoop::TYPE_DEFAULT, kRendererThreadStackSize,
base::kThreadPriority_High));
- submission_queue_.emplace(
- kMaxSubmissionQueueSize,
- base::TimeDelta::FromMillisecondsD(kTimeToConvergeInMS),
- base::Bind(&DestructSubmissionOnMessageLoop,
- submission_disposal_thread_.message_loop()));
+ ResetSubmissionQueue();
}
void Pipeline::ShutdownSubmissionQueue() {
@@ -622,5 +658,32 @@
}
}
+void Pipeline::ResetSubmissionQueue() {
+ TRACK_MEMORY_SCOPE("Renderer");
+ TRACE_EVENT0("cobalt::renderer", "Pipeline::ResetSubmissionQueue()");
+ submission_queue_ = base::nullopt;
+ submission_queue_.emplace(
+ current_timeline_info_.max_submission_queue_size,
+ base::TimeDelta::FromMillisecondsD(kTimeToConvergeInMS),
+ current_timeline_info_.allow_latency_reduction,
+ base::Bind(&DestructSubmissionOnMessageLoop,
+ submission_disposal_thread_.message_loop()));
+}
+
+void Pipeline::QueueSubmission(const Submission& submission,
+ base::TimeTicks receipt_time) {
+ TRACK_MEMORY_SCOPE("Renderer");
+ TRACE_EVENT0("cobalt::renderer", "Pipeline::QueueSubmission()");
+ // Upon each submission, check if the timeline has changed. If it has,
+ // reset our submission queue (possibly with a new configuration specified
+ // within |timeline_info|.
+ if (submission.timeline_info.id != current_timeline_info_.id) {
+ current_timeline_info_ = submission.timeline_info;
+ ResetSubmissionQueue();
+ }
+
+ submission_queue_->PushSubmission(submission, receipt_time);
+}
+
} // namespace renderer
} // namespace cobalt
diff --git a/src/cobalt/renderer/pipeline.h b/src/cobalt/renderer/pipeline.h
index 49308c9..f2c3663 100644
--- a/src/cobalt/renderer/pipeline.h
+++ b/src/cobalt/renderer/pipeline.h
@@ -93,6 +93,16 @@
void RasterizeToRGBAPixels(const Submission& render_tree_submission,
const RasterizationCompleteCallback& complete);
+ // Inserts a fence that ensures the rasterizer rasterizes up until the
+ // submission time proceeding queuing additional submissions. This is useful
+ // when switching timelines in order to ensure that an old timeline plays out
+ // completely before resetting the submission queue for a timeline change.
+ // Upon passing the fence, we will immediately queue the latest submission
+ // submitted after TimeFence() was called. If a time fence is set while
+ // an existing time fence already exists, the new time fence is ignored (and
+ // an error is logged).
+ void TimeFence(base::TimeDelta time_fence);
+
// Returns a thread-safe object from which one can produce renderer resources
// like images and fonts which can be referenced by render trees that are
// subsequently submitted to this pipeline.
@@ -125,7 +135,8 @@
// Updates the rasterizer timer stats according to the |start_time| and
// |end_time| of the most recent rasterize call.
- void UpdateRasterizeStats(bool did_rasterize, bool are_animations_active,
+ void UpdateRasterizeStats(bool did_rasterize,
+ bool are_stat_tracked_animations_expired,
bool is_new_render_tree, base::TimeTicks start_time,
base::TimeTicks end_time);
@@ -160,6 +171,17 @@
void FrameStatsOnFlushCallback(
const base::CValCollectionTimerStatsFlushResults& flush_results);
+ // Resets the submission queue, effecitvely emptying it and restarting it
+ // with the configuration specified by |current_timeline_info_| applied to it.
+ void ResetSubmissionQueue();
+
+ // Pushes the specified submission into the submission queue, where it will
+ // then be picked up by subsequent rasterizations. If the submission's
+ // timeline id is different from the current timeline id (in
+ // |current_timeline_info_|), then the submission queue will be reset.
+ void QueueSubmission(const Submission& submission,
+ base::TimeTicks receipt_time);
+
base::WaitableEvent rasterizer_created_event_;
// The render_target that all submitted render trees will be rasterized to.
@@ -214,6 +236,9 @@
// allows us to skip rasterizing that render tree if we see it again and it
// did have expired animations.
bool last_animations_expired_;
+ // Keep track of whether the last rendered tree had animations that we're
+ // tracking stats on.
+ bool last_stat_tracked_animations_expired_;
// Did a rasterization take place in the last frame?
bool last_did_rasterize_;
@@ -277,6 +302,18 @@
// True if the overlay has been updated and it needs to be re-rasterized.
bool fps_overlay_update_pending_;
+
+ // Time fence data that records if a time fence is active, at what time, and
+ // what submission if any is waiting to be queued once we pass the time fence.
+ base::optional<base::TimeDelta> time_fence_;
+ base::optional<Submission> post_fence_submission_;
+ base::optional<base::TimeTicks> post_fence_receipt_time_;
+
+ // Information about the current timeline. Each incoming submission
+ // identifies with a particular timeline, and if that ever changes, we assume
+ // a discontinuity in animations and reset our submission queue, possibly
+ // with new configuration parameters specified in the new |TimelineInfo|.
+ Submission::TimelineInfo current_timeline_info_;
};
} // namespace renderer
diff --git a/src/cobalt/renderer/rasterizer/egl/draw_object.cc b/src/cobalt/renderer/rasterizer/egl/draw_object.cc
index 24ec5d0..2e84809 100644
--- a/src/cobalt/renderer/rasterizer/egl/draw_object.cc
+++ b/src/cobalt/renderer/rasterizer/egl/draw_object.cc
@@ -73,8 +73,12 @@
rx(init.rx * kRCornerGradientScale),
ry(init.ry * kRCornerGradientScale) {}
+DrawObject::DrawObject()
+ : merge_type_(base::GetTypeId<DrawObject>()) {}
+
DrawObject::DrawObject(const BaseState& base_state)
- : base_state_(base_state) {}
+ : base_state_(base_state),
+ merge_type_(base::GetTypeId<DrawObject>()) {}
math::Vector2dF DrawObject::GetScale() const {
float m00 = base_state_.transform(0, 0);
diff --git a/src/cobalt/renderer/rasterizer/egl/draw_object.h b/src/cobalt/renderer/rasterizer/egl/draw_object.h
index 19af454..21ac722 100644
--- a/src/cobalt/renderer/rasterizer/egl/draw_object.h
+++ b/src/cobalt/renderer/rasterizer/egl/draw_object.h
@@ -71,6 +71,11 @@
virtual ~DrawObject() {}
+ // Certain draw objects can be merged with others to reduce the number of
+ // draw calls issued. If TryMerge returns true, then |other| can be discarded.
+ base::TypeId GetMergeTypeId() const { return merge_type_; }
+ virtual bool TryMerge(DrawObject* other) { return false; }
+
// This stage is used to update the vertex buffer for the rasterize
// stage. Vertex data is handled by the GraphicsState to minimize the number
// of vertex buffers needed. Once this stage is executed, the rasterizer will
@@ -107,7 +112,7 @@
RCorner rcorner;
};
- DrawObject() {}
+ DrawObject();
explicit DrawObject(const BaseState& base_state);
// Extract the scale vector from this object's transform.
@@ -147,6 +152,10 @@
BaseState base_state_;
+ // Provide type information for use with TryMerge. Only DrawObjects that may
+ // be merged need to set this.
+ base::TypeId merge_type_;
+
private:
// Return the RCorner values for the given rounded rect, and the normalized
// rect and corner values used.
diff --git a/src/cobalt/renderer/rasterizer/egl/draw_object_manager.cc b/src/cobalt/renderer/rasterizer/egl/draw_object_manager.cc
index e39eaaf..d12c4bc 100644
--- a/src/cobalt/renderer/rasterizer/egl/draw_object_manager.cc
+++ b/src/cobalt/renderer/rasterizer/egl/draw_object_manager.cc
@@ -44,6 +44,19 @@
BlendType blend_type, base::TypeId draw_type,
const backend::RenderTarget* render_target,
const math::RectF& draw_bounds) {
+ // See if this draw object can be merged with the last one.
+ if (!onscreen_draws_.empty()) {
+ DrawInfo& last_draw = onscreen_draws_.back();
+ if (last_draw.render_target == render_target &&
+ last_draw.draw_type == draw_type &&
+ last_draw.blend_type == blend_type &&
+ last_draw.draw_object->TryMerge(draw_object.get())) {
+ last_draw.draw_bounds.Union(draw_bounds);
+ last_draw.draw_id = ++current_draw_id_;
+ return current_draw_id_;
+ }
+ }
+
onscreen_draws_.emplace_back(draw_object.Pass(), draw_type, blend_type,
render_target, draw_bounds, ++current_draw_id_);
return current_draw_id_;
@@ -53,6 +66,19 @@
BlendType blend_type, base::TypeId draw_type,
const backend::RenderTarget* render_target,
const math::RectF& draw_bounds) {
+ // See if this draw object can be merged with the last one.
+ if (!offscreen_draws_.empty()) {
+ DrawInfo& last_draw = offscreen_draws_.back();
+ if (last_draw.render_target == render_target &&
+ last_draw.draw_type == draw_type &&
+ last_draw.blend_type == blend_type &&
+ last_draw.draw_object->TryMerge(draw_object.get())) {
+ last_draw.draw_bounds.Union(draw_bounds);
+ last_draw.draw_id = ++current_draw_id_;
+ return current_draw_id_;
+ }
+ }
+
offscreen_draws_.emplace_back(draw_object.Pass(), draw_type, blend_type,
render_target, draw_bounds, ++current_draw_id_);
return current_draw_id_;
@@ -65,7 +91,7 @@
RemoveDraws(&external_offscreen_draws_, last_valid_draw_id);
}
-void DrawObjectManager::RemoveDraws(std::vector<DrawInfo>* draw_list,
+void DrawObjectManager::RemoveDraws(DrawList* draw_list,
uint32_t last_valid_draw_id) {
// Objects in the draw list should have ascending draw IDs at this point.
auto iter = draw_list->end();
@@ -117,13 +143,13 @@
void DrawObjectManager::ExecuteOffscreenRasterize(GraphicsState* graphics_state,
ShaderProgramManager* program_manager) {
- SortOffscreenDraws(&external_offscreen_draws_);
+ SortOffscreenDraws(external_offscreen_draws_,
+ &sorted_external_offscreen_draws_);
// Process draws handled by an external rasterizer.
{
TRACE_EVENT0("cobalt::renderer", "OffscreenExternalRasterizer");
- for (auto draw = external_offscreen_draws_.begin();
- draw != external_offscreen_draws_.end(); ++draw) {
+ for (const DrawInfo* draw : sorted_external_offscreen_draws_) {
// Batched external draws should not have any dependencies.
DCHECK_EQ(draw->dependencies, 0);
draw->draw_object->ExecuteRasterize(graphics_state, program_manager);
@@ -133,8 +159,8 @@
}
}
- SortOffscreenDraws(&offscreen_draws_);
- SortOnscreenDraws(&onscreen_draws_);
+ SortOffscreenDraws(offscreen_draws_, &sorted_offscreen_draws_);
+ SortOnscreenDraws(onscreen_draws_, &sorted_onscreen_draws_);
// Update the vertex buffer for all draws.
{
@@ -145,19 +171,17 @@
// Process the native offscreen draws.
{
TRACE_EVENT0("cobalt::renderer", "OffscreenNativeRasterizer");
- Rasterize(offscreen_draws_, graphics_state, program_manager);
+ Rasterize(sorted_offscreen_draws_, graphics_state, program_manager);
}
}
void DrawObjectManager::ExecuteUpdateVertexBuffer(
GraphicsState* graphics_state, ShaderProgramManager* program_manager) {
- for (auto draw = offscreen_draws_.begin(); draw != offscreen_draws_.end();
- ++draw) {
+ for (const DrawInfo* draw : sorted_offscreen_draws_) {
draw->draw_object->ExecuteUpdateVertexBuffer(
graphics_state, program_manager);
}
- for (auto draw = onscreen_draws_.begin(); draw != onscreen_draws_.end();
- ++draw) {
+ for (const DrawInfo* draw : sorted_onscreen_draws_) {
draw->draw_object->ExecuteUpdateVertexBuffer(
graphics_state, program_manager);
}
@@ -166,10 +190,10 @@
void DrawObjectManager::ExecuteOnscreenRasterize(GraphicsState* graphics_state,
ShaderProgramManager* program_manager) {
- Rasterize(onscreen_draws_, graphics_state, program_manager);
+ Rasterize(sorted_onscreen_draws_, graphics_state, program_manager);
}
-void DrawObjectManager::Rasterize(const std::vector<DrawInfo>& draw_list,
+void DrawObjectManager::Rasterize(const SortedDrawList& sorted_draw_list,
GraphicsState* graphics_state, ShaderProgramManager* program_manager) {
const backend::RenderTarget* current_target = nullptr;
bool using_native_rasterizer = true;
@@ -177,7 +201,7 @@
// Starting from an unknown state.
graphics_state->SetDirty();
- for (auto draw = draw_list.begin(); draw != draw_list.end(); ++draw) {
+ for (const DrawInfo* draw : sorted_draw_list) {
bool draw_uses_native_rasterizer = draw->blend_type != kBlendExternal;
if (draw_uses_native_rasterizer) {
@@ -217,94 +241,131 @@
}
}
-void DrawObjectManager::SortOffscreenDraws(std::vector<DrawInfo>* draw_list) {
+void DrawObjectManager::SortOffscreenDraws(const DrawList& draw_list,
+ SortedDrawList* sorted_draw_list) {
TRACE_EVENT0("cobalt::renderer", "SortOffscreenDraws");
// Sort offscreen draws to minimize GPU state changes.
- for (auto iter = draw_list->begin(); iter != draw_list->end(); ++iter) {
+ sorted_draw_list->reserve(draw_list.size());
+ for (size_t draw_pos = 0; draw_pos < draw_list.size(); ++draw_pos) {
+ auto* draw = &draw_list[draw_pos];
+ bool draw_uses_native_rasterizer = draw->blend_type != kBlendExternal;
+ bool next_uses_native_rasterizer = draw_pos + 1 < draw_list.size() &&
+ draw_list[draw_pos + 1].blend_type != kBlendExternal;
auto dependencies =
- dependency_count_.find(iter->render_target->GetSerialNumber());
- iter->dependencies =
+ dependency_count_.find(draw->render_target->GetSerialNumber());
+ draw->dependencies =
dependencies != dependency_count_.end() ? dependencies->second : 0;
- for (auto current_draw = iter; current_draw != draw_list->begin();
- std::swap(*current_draw, *(current_draw - 1)), current_draw--) {
- auto prev_draw = current_draw - 1;
+ // Find an appropriate sort position for the current draw.
+ auto sort_pos = draw_pos;
+ for (; sort_pos > 0; --sort_pos) {
+ auto* prev_draw = sorted_draw_list->at(sort_pos - 1);
// Unlike onscreen draws, offscreen draws should be grouped by render
// target. Ensure that render targets with fewer dependencies are first
// in the draw list.
- if (prev_draw->dependencies > current_draw->dependencies) {
+ if (prev_draw->dependencies > draw->dependencies) {
continue;
- } else if (prev_draw->dependencies < current_draw->dependencies) {
+ } else if (prev_draw->dependencies < draw->dependencies) {
break;
}
- if (prev_draw->render_target > current_draw->render_target) {
+ if (prev_draw->render_target > draw->render_target) {
continue;
- } else if (prev_draw->render_target < current_draw->render_target) {
+ } else if (prev_draw->render_target < draw->render_target) {
break;
}
- if (prev_draw->draw_bounds.Intersects(current_draw->draw_bounds)) {
- break;
- }
-
- if (prev_draw->draw_type > current_draw->draw_type) {
- continue;
- } else if (prev_draw->draw_type < current_draw->draw_type) {
- break;
- }
-
- if (prev_draw->blend_type <= current_draw->blend_type) {
- break;
- }
- }
- }
-}
-
-void DrawObjectManager::SortOnscreenDraws(std::vector<DrawInfo>* draw_list) {
- TRACE_EVENT0("cobalt::renderer", "SortOnscreenDraws");
-
- // Sort onscreen draws to minimize GPU state changes.
- for (auto iter = draw_list->begin(); iter != draw_list->end(); ++iter) {
- for (auto current_draw = iter; current_draw != draw_list->begin();
- std::swap(*current_draw, *(current_draw - 1)), current_draw--) {
- auto prev_draw = current_draw - 1;
-
- // Do not sort across different render targets since their contents may
- // be generated just before consumed by a subsequent draw.
- if (prev_draw->render_target != current_draw->render_target) {
- break;
- }
-
- if (prev_draw->draw_bounds.Intersects(current_draw->draw_bounds)) {
+ // The rest of the sorting logic is the same between onscreen and
+ // offscreen draws.
+ if (prev_draw->draw_bounds.Intersects(draw->draw_bounds)) {
break;
}
// Group native vs. non-native draws together.
- bool next_uses_same_rasterizer = current_draw + 1 != draw_list->end() &&
- ((current_draw + 1)->blend_type == kBlendExternal) ==
- (current_draw->blend_type == kBlendExternal);
- bool prev_uses_same_rasterizer =
- (prev_draw->blend_type == kBlendExternal) ==
- (current_draw->blend_type == kBlendExternal);
- if (!next_uses_same_rasterizer && !prev_uses_same_rasterizer) {
+ bool prev_uses_native_rasterizer =
+ prev_draw->blend_type != kBlendExternal;
+ if (draw_uses_native_rasterizer != next_uses_native_rasterizer &&
+ draw_uses_native_rasterizer != prev_uses_native_rasterizer) {
+ next_uses_native_rasterizer = prev_uses_native_rasterizer;
continue;
}
- if (next_uses_same_rasterizer && !prev_uses_same_rasterizer) {
+ if (draw_uses_native_rasterizer == next_uses_native_rasterizer &&
+ draw_uses_native_rasterizer != prev_uses_native_rasterizer) {
+ break;
+ }
+ next_uses_native_rasterizer = prev_uses_native_rasterizer;
+
+ if (prev_draw->draw_type > draw->draw_type) {
+ continue;
+ } else if (prev_draw->draw_type < draw->draw_type) {
break;
}
- if (prev_draw->draw_type > current_draw->draw_type) {
- continue;
- } else if (prev_draw->draw_type < current_draw->draw_type) {
- break;
- }
-
- if (prev_draw->blend_type <= current_draw->blend_type) {
+ if (prev_draw->blend_type <= draw->blend_type) {
break;
}
}
+
+ sorted_draw_list->insert(sorted_draw_list->begin() + sort_pos, draw);
+ }
+}
+
+void DrawObjectManager::SortOnscreenDraws(const DrawList& draw_list,
+ SortedDrawList* sorted_draw_list) {
+ TRACE_EVENT0("cobalt::renderer", "SortOnscreenDraws");
+
+ // Sort onscreen draws to minimize GPU state changes.
+ sorted_draw_list->reserve(draw_list.size());
+ for (size_t draw_pos = 0; draw_pos < draw_list.size(); ++draw_pos) {
+ auto* draw = &draw_list[draw_pos];
+ bool draw_uses_native_rasterizer = draw->blend_type != kBlendExternal;
+ bool next_uses_native_rasterizer = draw_pos + 1 < draw_list.size() &&
+ draw_list[draw_pos + 1].blend_type != kBlendExternal;
+
+ // Find an appropriate sort position for the current draw.
+ auto sort_pos = draw_pos;
+ for (; sort_pos > 0; --sort_pos) {
+ auto* prev_draw = sorted_draw_list->at(sort_pos - 1);
+
+ // Do not sort across different render targets since their contents may
+ // be generated just before consumed by a subsequent draw.
+ if (prev_draw->render_target != draw->render_target) {
+ break;
+ }
+
+ // The rest of the sorting logic is the same between onscreen and
+ // offscreen draws.
+ if (prev_draw->draw_bounds.Intersects(draw->draw_bounds)) {
+ break;
+ }
+
+ // Group native vs. non-native draws together.
+ bool prev_uses_native_rasterizer =
+ prev_draw->blend_type != kBlendExternal;
+ if (draw_uses_native_rasterizer != next_uses_native_rasterizer &&
+ draw_uses_native_rasterizer != prev_uses_native_rasterizer) {
+ next_uses_native_rasterizer = prev_uses_native_rasterizer;
+ continue;
+ }
+ if (draw_uses_native_rasterizer == next_uses_native_rasterizer &&
+ draw_uses_native_rasterizer != prev_uses_native_rasterizer) {
+ break;
+ }
+ next_uses_native_rasterizer = prev_uses_native_rasterizer;
+
+ if (prev_draw->draw_type > draw->draw_type) {
+ continue;
+ } else if (prev_draw->draw_type < draw->draw_type) {
+ break;
+ }
+
+ if (prev_draw->blend_type <= draw->blend_type) {
+ break;
+ }
+ }
+
+ sorted_draw_list->insert(sorted_draw_list->begin() + sort_pos, draw);
}
}
diff --git a/src/cobalt/renderer/rasterizer/egl/draw_object_manager.h b/src/cobalt/renderer/rasterizer/egl/draw_object_manager.h
index 10b0f17..beb941e 100644
--- a/src/cobalt/renderer/rasterizer/egl/draw_object_manager.h
+++ b/src/cobalt/renderer/rasterizer/egl/draw_object_manager.h
@@ -117,7 +117,7 @@
BlendType blend_type;
union {
uint32_t draw_id;
- uint32_t dependencies;
+ mutable uint32_t dependencies;
};
};
@@ -130,25 +130,33 @@
const backend::RenderTarget* required_target;
};
+ typedef std::vector<DrawInfo> DrawList;
+ typedef std::vector<const DrawInfo*> SortedDrawList;
+
void ExecuteUpdateVertexBuffer(GraphicsState* graphics_state,
ShaderProgramManager* program_manager);
- void Rasterize(const std::vector<DrawInfo>& draw_list,
+ void Rasterize(const SortedDrawList& draw_list,
GraphicsState* graphics_state,
ShaderProgramManager* program_manager);
- void RemoveDraws(std::vector<DrawInfo>* draw_list,
- uint32_t last_valid_draw_id);
+ void RemoveDraws(DrawList* draw_list, uint32_t last_valid_draw_id);
- void SortOffscreenDraws(std::vector<DrawInfo>* draw_list);
- void SortOnscreenDraws(std::vector<DrawInfo>* draw_list);
+ void SortOffscreenDraws(const DrawList& draw_list,
+ SortedDrawList* sorted_draw_list);
+ void SortOnscreenDraws(const DrawList& draw_list,
+ SortedDrawList* sorted_draw_list);
base::Closure reset_external_rasterizer_;
base::Closure flush_external_offscreen_draws_;
- std::vector<DrawInfo> onscreen_draws_;
- std::vector<DrawInfo> offscreen_draws_;
- std::vector<DrawInfo> external_offscreen_draws_;
+ DrawList onscreen_draws_;
+ DrawList offscreen_draws_;
+ DrawList external_offscreen_draws_;
+
+ SortedDrawList sorted_onscreen_draws_;
+ SortedDrawList sorted_offscreen_draws_;
+ SortedDrawList sorted_external_offscreen_draws_;
std::vector<RenderTargetDependency> draw_dependencies_;
std::unordered_map<int32_t, uint32_t> dependency_count_;
diff --git a/src/cobalt/renderer/rasterizer/egl/draw_poly_color.cc b/src/cobalt/renderer/rasterizer/egl/draw_poly_color.cc
index d56c717..eda1511 100644
--- a/src/cobalt/renderer/rasterizer/egl/draw_poly_color.cc
+++ b/src/cobalt/renderer/rasterizer/egl/draw_poly_color.cc
@@ -16,6 +16,8 @@
#include <GLES2/gl2.h>
+#include "base/logging.h"
+#include "cobalt/base/polymorphic_downcast.h"
#include "cobalt/renderer/backend/egl/utils.h"
#include "egl/generated_shader_impl.h"
#include "starboard/memory.h"
@@ -29,32 +31,77 @@
const BaseState& base_state, const math::RectF& rect,
const render_tree::ColorRGBA& color)
: DrawObject(base_state),
- vertex_buffer_(NULL) {
+ index_buffer_(nullptr),
+ vertex_buffer_(nullptr) {
+ merge_type_ = base::GetTypeId<DrawPolyColor>();
+
attributes_.reserve(4);
- AddRect(rect, GetGLRGBA(GetDrawColor(color) * base_state_.opacity));
+ AddRectVertices(rect, GetGLRGBA(GetDrawColor(color) * base_state_.opacity));
+ indices_.reserve(6);
+ AddRectIndices(0, 1, 2, 3);
+
graphics_state->ReserveVertexData(
- attributes_.size() * sizeof(VertexAttributes));
+ attributes_.size() * sizeof(attributes_[0]));
+ graphics_state->ReserveVertexIndices(indices_.size());
}
DrawPolyColor::DrawPolyColor(const BaseState& base_state)
: DrawObject(base_state),
- vertex_buffer_(NULL) {
+ index_buffer_(nullptr),
+ vertex_buffer_(nullptr) {
+ merge_type_ = base::GetTypeId<DrawPolyColor>();
+}
+
+bool DrawPolyColor::TryMerge(DrawObject* other) {
+ if (merge_type_ != other->GetMergeTypeId()) {
+ return false;
+ }
+
+ // If the merge types match, then the objects should use the same shaders.
+ // Otherwise, ensure the merge types are different.
+ DCHECK(GetTypeId() == other->GetTypeId());
+
+ DrawPolyColor* merge = base::polymorphic_downcast<DrawPolyColor*>(other);
+ if (!PrepareForMerge() || !merge->PrepareForMerge()) {
+ return false;
+ }
+
+ // Since the draws for these objects already use indexed triangles, just
+ // concatenate the vertex attributes and indices. Keep in mind the indices
+ // for the |other| object need to be fixed up.
+ uint16_t index_offset = static_cast<uint16_t>(attributes_.size());
+ attributes_.insert(attributes_.end(),
+ merge->attributes_.begin(), merge->attributes_.end());
+ for (uint16_t index : merge->indices_) {
+ indices_.emplace_back(index + index_offset);
+ }
+
+ base_state_.scissor.Union(merge->base_state_.scissor);
+ return true;
}
void DrawPolyColor::ExecuteUpdateVertexBuffer(
GraphicsState* graphics_state,
ShaderProgramManager* program_manager) {
- vertex_buffer_ = graphics_state->AllocateVertexData(
- attributes_.size() * sizeof(VertexAttributes));
- SbMemoryCopy(vertex_buffer_, &attributes_[0],
- attributes_.size() * sizeof(VertexAttributes));
+ if (attributes_.size() > 0) {
+ vertex_buffer_ = graphics_state->AllocateVertexData(
+ attributes_.size() * sizeof(attributes_[0]));
+ SbMemoryCopy(vertex_buffer_, &attributes_[0],
+ attributes_.size() * sizeof(attributes_[0]));
+ index_buffer_ = graphics_state->AllocateVertexIndices(indices_.size());
+ SbMemoryCopy(index_buffer_, &indices_[0],
+ indices_.size() * sizeof(indices_[0]));
+ }
}
void DrawPolyColor::ExecuteRasterize(
GraphicsState* graphics_state,
ShaderProgramManager* program_manager) {
- SetupShader(graphics_state, program_manager);
- GL_CALL(glDrawArrays(GL_TRIANGLE_STRIP, 0, attributes_.size()));
+ if (attributes_.size() > 0) {
+ SetupShader(graphics_state, program_manager);
+ GL_CALL(glDrawElements(GL_TRIANGLES, indices_.size(), GL_UNSIGNED_SHORT,
+ graphics_state->GetVertexIndexPointer(index_buffer_)));
+ }
}
base::TypeId DrawPolyColor::GetTypeId() const {
@@ -86,16 +133,55 @@
graphics_state->VertexAttribFinish();
}
-void DrawPolyColor::AddRect(const math::RectF& rect, uint32_t color) {
- AddVertex(rect.x(), rect.y(), color);
- AddVertex(rect.x(), rect.bottom(), color);
- AddVertex(rect.right(), rect.y(), color);
- AddVertex(rect.right(), rect.bottom(), color);
+void DrawPolyColor::AddRectVertices(const math::RectF& rect, uint32_t color) {
+ // Beware that child classes may depend on the order in which these vertices
+ // are added.
+ attributes_.emplace_back(rect.x(), rect.y(), color);
+ attributes_.emplace_back(rect.right(), rect.y(), color);
+ attributes_.emplace_back(rect.x(), rect.bottom(), color);
+ attributes_.emplace_back(rect.right(), rect.bottom(), color);
}
-void DrawPolyColor::AddVertex(float x, float y, uint32_t color) {
- VertexAttributes attribute = { { x, y }, color };
- attributes_.push_back(attribute);
+void DrawPolyColor::AddRectIndices(uint16_t top_left, uint16_t top_right,
+ uint16_t bottom_left, uint16_t bottom_right) {
+ indices_.emplace_back(top_left);
+ indices_.emplace_back(top_right);
+ indices_.emplace_back(bottom_left);
+ indices_.emplace_back(top_right);
+ indices_.emplace_back(bottom_left);
+ indices_.emplace_back(bottom_right);
+}
+
+bool DrawPolyColor::PrepareForMerge() {
+ if (can_merge_) {
+ return *can_merge_;
+ }
+
+ // Since a single draw can only have one transform and one scissor, draws
+ // can be merged only if they use the same transform and the vertices are
+ // in their respective scissors.
+
+ // Rounded scissors are too expensive to check for containment.
+ if (base_state_.rounded_scissor_corners) {
+ can_merge_ = false;
+ return *can_merge_;
+ }
+
+ math::RectF scissor(base_state_.scissor);
+ bool in_scissor = true;
+
+ // Transform the vertices and check that they are within the scissor.
+ for (auto& vert : attributes_) {
+ math::PointF pos = base_state_.transform *
+ math::PointF(vert.position[0], vert.position[1]);
+ vert.position[0] = pos.x();
+ vert.position[1] = pos.y();
+ in_scissor = in_scissor && scissor.Contains(pos);
+ }
+
+ base_state_.transform = math::Matrix3F::Identity();
+ can_merge_ = in_scissor;
+ return *can_merge_;
}
} // namespace egl
diff --git a/src/cobalt/renderer/rasterizer/egl/draw_poly_color.h b/src/cobalt/renderer/rasterizer/egl/draw_poly_color.h
index cfce106..356ebf5 100644
--- a/src/cobalt/renderer/rasterizer/egl/draw_poly_color.h
+++ b/src/cobalt/renderer/rasterizer/egl/draw_poly_color.h
@@ -17,6 +17,7 @@
#include <vector>
+#include "base/optional.h"
#include "cobalt/math/rect_f.h"
#include "cobalt/render_tree/color_rgba.h"
#include "cobalt/renderer/rasterizer/egl/draw_object.h"
@@ -34,6 +35,7 @@
const math::RectF& rect,
const render_tree::ColorRGBA& color);
+ bool TryMerge(DrawObject* other) OVERRIDE;
void ExecuteUpdateVertexBuffer(GraphicsState* graphics_state,
ShaderProgramManager* program_manager) OVERRIDE;
void ExecuteRasterize(GraphicsState* graphics_state,
@@ -44,16 +46,26 @@
explicit DrawPolyColor(const BaseState& base_state);
void SetupShader(GraphicsState* graphics_state,
ShaderProgramManager* program_manager);
- void AddRect(const math::RectF& rect, uint32_t color);
- void AddVertex(float x, float y, uint32_t color);
+ void AddRectVertices(const math::RectF& rect, uint32_t color);
+ void AddRectIndices(uint16_t top_left, uint16_t top_right,
+ uint16_t bottom_left, uint16_t bottom_right);
+ bool PrepareForMerge();
struct VertexAttributes {
+ VertexAttributes(float x, float y, uint32_t color32) {
+ position[0] = x;
+ position[1] = y;
+ color = color32;
+ }
float position[2];
uint32_t color;
};
std::vector<VertexAttributes> attributes_;
+ std::vector<uint16_t> indices_;
+ uint16_t* index_buffer_;
uint8_t* vertex_buffer_;
+ base::optional<bool> can_merge_;
};
} // namespace egl
diff --git a/src/cobalt/renderer/rasterizer/egl/draw_rect_border.cc b/src/cobalt/renderer/rasterizer/egl/draw_rect_border.cc
index f3d38c7..e24392d 100644
--- a/src/cobalt/renderer/rasterizer/egl/draw_rect_border.cc
+++ b/src/cobalt/renderer/rasterizer/egl/draw_rect_border.cc
@@ -32,20 +32,24 @@
// antialiased inner area, and the solid area in between.
const int kRegionCount = 3;
-// Each region consists of 2 rects which use 4 vertices each. Each region is
-// drawn with 8 triangles, and indices are used to minimize vertex duplication.
-const int kVertexCountPerRegion = 4 * 2;
-const int kIndexCountPerRegion = 8 * 3;
+// Each region consists of an outer and inner rectangle. However, since regions
+// are adjacent to each other, many of these rectangles are shared.
+const int kVertexCount = (kRegionCount + 1) * 4;
-const int kVertexCount = kRegionCount * kVertexCountPerRegion;
-const int kIndexCount = kRegionCount * kIndexCountPerRegion;
+// The draw object may draw the content rect as well. If so, two triangles are
+// used to draw the content rect.
+const int kIndexCountForContentRect = 2 * 3;
+
+// Each region has 4 rectangular areas corresponding to the possible borders.
+// Each rectangular area is drawn using 2 triangles.
+const int kIndexCount = kRegionCount * (4 * 2 * 3) + kIndexCountForContentRect;
} // namespace
DrawRectBorder::DrawRectBorder(GraphicsState* graphics_state,
const BaseState& base_state,
const scoped_refptr<render_tree::RectNode>& node)
: DrawPolyColor(base_state),
- index_buffer_(NULL) {
+ draw_content_rect_(false) {
DCHECK(node->data().border);
const render_tree::Border& border = *(node->data().border);
@@ -99,17 +103,24 @@
(num_borders == 2 && uniform_opposing_borders) ||
(num_borders == 4 && uniform_borders));
- // If a background brush is used, then only solid colored ones are supported.
- // This simplifies blending the inner-antialiased border with the content.
+ // If the background brush is solid-colored, then this object can handle the
+ // content rect as well. Otherwise, don't draw the inner antialiased edge to
+ // avoid having to blend with an unknown color.
render_tree::ColorRGBA content_color(0);
- if (is_valid_ && node->data().background_brush) {
- is_valid_ = node->data().background_brush->GetTypeId() ==
- base::GetTypeId<render_tree::SolidColorBrush>();
- if (is_valid_) {
- const render_tree::SolidColorBrush* solid_brush =
- base::polymorphic_downcast<const render_tree::SolidColorBrush*>
- (node->data().background_brush.get());
- content_color = GetDrawColor(solid_brush->color()) * base_state_.opacity;
+ if (is_valid_) {
+ if (node->data().background_brush) {
+ draw_content_rect_ = node->data().background_brush->GetTypeId() ==
+ base::GetTypeId<render_tree::SolidColorBrush>();
+ if (draw_content_rect_) {
+ const render_tree::SolidColorBrush* solid_brush =
+ base::polymorphic_downcast<const render_tree::SolidColorBrush*>
+ (node->data().background_brush.get());
+ content_color = GetDrawColor(solid_brush->color()) *
+ base_state_.opacity;
+ }
+ } else {
+ // No background brush is the same as a totally transparent background.
+ draw_content_rect_ = true;
}
}
@@ -127,37 +138,13 @@
border_color, content_color);
if (is_valid_ && attributes_.size() > 0) {
graphics_state->ReserveVertexData(
- attributes_.size() * sizeof(VertexAttributes));
+ attributes_.size() * sizeof(attributes_[0]));
graphics_state->ReserveVertexIndices(indices_.size());
}
}
}
}
-void DrawRectBorder::ExecuteUpdateVertexBuffer(
- GraphicsState* graphics_state,
- ShaderProgramManager* program_manager) {
- if (attributes_.size() > 0) {
- vertex_buffer_ = graphics_state->AllocateVertexData(
- attributes_.size() * sizeof(VertexAttributes));
- SbMemoryCopy(vertex_buffer_, &attributes_[0],
- attributes_.size() * sizeof(VertexAttributes));
- index_buffer_ = graphics_state->AllocateVertexIndices(indices_.size());
- SbMemoryCopy(index_buffer_, &indices_[0],
- indices_.size() * sizeof(indices_[0]));
- }
-}
-
-void DrawRectBorder::ExecuteRasterize(
- GraphicsState* graphics_state,
- ShaderProgramManager* program_manager) {
- if (attributes_.size() > 0) {
- SetupShader(graphics_state, program_manager);
- GL_CALL(glDrawElements(GL_TRIANGLES, indices_.size(), GL_UNSIGNED_SHORT,
- graphics_state->GetVertexIndexPointer(index_buffer_)));
- }
-}
-
bool DrawRectBorder::SetSquareBorder(const render_tree::Border& border,
const math::RectF& border_rect, const math::RectF& content_rect,
const render_tree::ColorRGBA& border_color,
@@ -196,17 +183,41 @@
math::RectF outer_rect(border_rect);
math::RectF inner_rect(content_rect);
outer_rect.Inset(insets.Scale(0.5f * pixel_size_x, 0.5f * pixel_size_y));
- inner_rect.Inset(insets.Scale(-0.5f * pixel_size_x, -0.5f * pixel_size_y));
+ if (draw_content_rect_) {
+ inner_rect.Inset(insets.Scale(-0.5f * pixel_size_x, -0.5f * pixel_size_y));
+ }
math::RectF outer_outer(outer_rect);
math::RectF inner_inner(inner_rect);
outer_outer.Inset(insets.Scale(-pixel_size_x, -pixel_size_y));
- inner_inner.Inset(insets.Scale(pixel_size_x, pixel_size_y));
+ if (draw_content_rect_) {
+ inner_inner.Inset(insets.Scale(pixel_size_x, pixel_size_y));
+ }
- uint32_t border_color32 = GetGLRGBA(border_color);
- uint32_t content_color32 = GetGLRGBA(content_color);
- AddRegion(outer_outer, 0, outer_rect, border_color32);
- AddRegion(outer_rect, border_color32, inner_rect, border_color32);
- AddRegion(inner_rect, border_color32, inner_inner, content_color32);
+ // Add the vertex attributes for the rectangles that will be used.
+ uint16_t outer_outer_verts = static_cast<uint16_t>(attributes_.size());
+ AddRectVertices(outer_outer, 0);
+ uint16_t outer_rect_verts = static_cast<uint16_t>(attributes_.size());
+ AddRectVertices(outer_rect, GetGLRGBA(border_color));
+ uint16_t inner_rect_verts = static_cast<uint16_t>(attributes_.size());
+ AddRectVertices(inner_rect, GetGLRGBA(border_color));
+ uint16_t inner_inner_verts = inner_rect_verts;
+ if (draw_content_rect_) {
+ inner_inner_verts = static_cast<uint16_t>(attributes_.size());
+ AddRectVertices(inner_inner, GetGLRGBA(content_color));
+ }
+
+ // Add indices to draw the borders using the vertex attributes added.
+ AddBorders(border, outer_outer_verts, outer_rect_verts);
+ AddBorders(border, outer_rect_verts, inner_rect_verts);
+ if (draw_content_rect_) {
+ AddBorders(border, inner_rect_verts, inner_inner_verts);
+ }
+
+ // Draw the content rect as appropriate.
+ if (draw_content_rect_ && content_color.a() > 0.0f) {
+ AddRectIndices(inner_inner_verts, inner_inner_verts + 1,
+ inner_inner_verts + 2, inner_inner_verts + 3);
+ }
// Update the content and node bounds to account for the antialiasing edges.
node_bounds_ = outer_outer;
@@ -214,34 +225,27 @@
return true;
}
-void DrawRectBorder::AddRegion(
- const math::RectF& outer_rect, uint32_t outer_color,
- const math::RectF& inner_rect, uint32_t inner_color) {
- // Add triangles to render the area between the two rects.
- uint16_t first_vertex = static_cast<uint16_t>(attributes_.size());
- AddVertex(outer_rect.x(), outer_rect.y(), outer_color);
- AddVertex(inner_rect.x(), inner_rect.y(), inner_color);
- AddVertex(outer_rect.right(), outer_rect.y(), outer_color);
- AddVertex(inner_rect.right(), inner_rect.y(), inner_color);
- AddVertex(outer_rect.right(), outer_rect.bottom(), outer_color);
- AddVertex(inner_rect.right(), inner_rect.bottom(), inner_color);
- AddVertex(outer_rect.x(), outer_rect.bottom(), outer_color);
- AddVertex(inner_rect.x(), inner_rect.bottom(), inner_color);
-
- // Use indices to minimize duplication of vertex data. The last two triangles
- // use the first one or two vertices of the region.
- uint16_t wrap_start = static_cast<uint16_t>(attributes_.size()) - 2;
- for (uint16_t i = first_vertex; i < wrap_start; ++i) {
- indices_.push_back(i);
- indices_.push_back(i + 1);
- indices_.push_back(i + 2);
+void DrawRectBorder::AddBorders(const render_tree::Border& border,
+ uint16_t outer_verts, uint16_t inner_verts) {
+ // Draw the area between those two rectangles using triangle primitives.
+ // The vertices for the rectangles were added as top-left, top-right,
+ // bottom-left, and bottom-right. See DrawPolyColor::AddRectVertices().
+ if (border.left.style != render_tree::kBorderStyleNone) {
+ AddRectIndices(outer_verts, inner_verts,
+ outer_verts + 2, inner_verts + 2);
}
- indices_.push_back(wrap_start);
- indices_.push_back(wrap_start + 1);
- indices_.push_back(first_vertex);
- indices_.push_back(wrap_start + 1);
- indices_.push_back(first_vertex);
- indices_.push_back(first_vertex + 1);
+ if (border.top.style != render_tree::kBorderStyleNone) {
+ AddRectIndices(outer_verts, outer_verts + 1,
+ inner_verts, inner_verts + 1);
+ }
+ if (border.right.style != render_tree::kBorderStyleNone) {
+ AddRectIndices(inner_verts + 1, outer_verts + 1,
+ inner_verts + 3, outer_verts + 3);
+ }
+ if (border.bottom.style != render_tree::kBorderStyleNone) {
+ AddRectIndices(inner_verts + 2, inner_verts + 3,
+ outer_verts + 2, outer_verts + 3);
+ }
}
} // namespace egl
diff --git a/src/cobalt/renderer/rasterizer/egl/draw_rect_border.h b/src/cobalt/renderer/rasterizer/egl/draw_rect_border.h
index 5139fff..2944611 100644
--- a/src/cobalt/renderer/rasterizer/egl/draw_rect_border.h
+++ b/src/cobalt/renderer/rasterizer/egl/draw_rect_border.h
@@ -35,12 +35,8 @@
const BaseState& base_state,
const scoped_refptr<render_tree::RectNode>& node);
- void ExecuteUpdateVertexBuffer(GraphicsState* graphics_state,
- ShaderProgramManager* program_manager) OVERRIDE;
- void ExecuteRasterize(GraphicsState* graphics_state,
- ShaderProgramManager* program_manager) OVERRIDE;
-
bool IsValid() const { return is_valid_; }
+ bool DrawsContentRect() const { return draw_content_rect_; }
const math::RectF& GetContentRect() const { return content_rect_; }
const math::RectF& GetBounds() const { return node_bounds_; }
@@ -50,14 +46,13 @@
const math::RectF& content_rect,
const render_tree::ColorRGBA& border_color,
const render_tree::ColorRGBA& content_color);
- void AddRegion(const math::RectF& outer_rect, uint32_t outer_color,
- const math::RectF& inner_rect, uint32_t inner_color);
+ void AddBorders(const render_tree::Border& border,
+ uint16_t outer_verts, uint16_t inner_verts);
math::RectF content_rect_;
math::RectF node_bounds_;
- std::vector<uint16_t> indices_;
- uint16_t* index_buffer_;
bool is_valid_;
+ bool draw_content_rect_;
};
} // namespace egl
diff --git a/src/cobalt/renderer/rasterizer/egl/render_tree_node_visitor.cc b/src/cobalt/renderer/rasterizer/egl/render_tree_node_visitor.cc
index 49b9243..fad5a3b 100644
--- a/src/cobalt/renderer/rasterizer/egl/render_tree_node_visitor.cc
+++ b/src/cobalt/renderer/rasterizer/egl/render_tree_node_visitor.cc
@@ -520,7 +520,11 @@
}
if (draw_border) {
+ bool content_rect_drawn = draw_border->DrawsContentRect();
AddTransparentDraw(draw_border.PassAs<DrawObject>(), node_bounds);
+ if (content_rect_drawn) {
+ return;
+ }
}
// Handle drawing the content.
@@ -537,11 +541,9 @@
} else {
scoped_ptr<DrawObject> draw(new DrawPolyColor(graphics_state_,
draw_state_, content_rect, solid_brush->color()));
- if (IsOpaque(draw_state_.opacity * solid_brush->color().a())) {
- AddOpaqueDraw(draw.Pass(), node_bounds);
- } else {
- AddTransparentDraw(draw.Pass(), node_bounds);
- }
+ // Match the blending mode used by other rect node draws to allow
+ // merging of the draw objects if possible.
+ AddTransparentDraw(draw.Pass(), node_bounds);
}
} else if (brush_is_linear_and_supported) {
const render_tree::LinearGradientBrush* linear_brush =
diff --git a/src/cobalt/renderer/rasterizer/lib/exported/graphics.h b/src/cobalt/renderer/rasterizer/lib/exported/graphics.h
index 0163934..7543fcf 100644
--- a/src/cobalt/renderer/rasterizer/lib/exported/graphics.h
+++ b/src/cobalt/renderer/rasterizer/lib/exported/graphics.h
@@ -31,6 +31,12 @@
extern "C" {
#endif
+typedef struct CbLibSize {
+ CbLibSize(int width, int height) : width(width), height(height) {}
+ int width;
+ int height;
+} CbLibSize;
+
typedef void (*CbLibGraphicsContextCreatedCallback)(void* context);
typedef void (*CbLibGraphicsBeginRenderFrameCallback)(void* context);
typedef void (*CbLibGraphicsEndRenderFrameCallback)(void* context);
@@ -59,6 +65,13 @@
// rasterization thread only.
SB_EXPORT_PLATFORM intptr_t CbLibGrapicsGetMainTextureHandle();
+// Sets the target main texture buffer size (in pixels) to use when rendering
+// out HTML content. The specified size is a target and is not guaranteed. In
+// general, the updated size will be picked up and used at the beginning of the
+// next frame.
+SB_EXPORT_PLATFORM void CbLibGraphicsSetTargetMainTextureSize(
+ const CbLibSize& target_render_size);
+
#ifdef __cplusplus
} // extern "C"
#endif
diff --git a/src/cobalt/renderer/rasterizer/lib/external_rasterizer.cc b/src/cobalt/renderer/rasterizer/lib/external_rasterizer.cc
index 1ac6887..4838ed8 100644
--- a/src/cobalt/renderer/rasterizer/lib/external_rasterizer.cc
+++ b/src/cobalt/renderer/rasterizer/lib/external_rasterizer.cc
@@ -34,6 +34,8 @@
#include "cobalt/renderer/rasterizer/skia/hardware_mesh.h"
#include "cobalt/renderer/rasterizer/skia/hardware_rasterizer.h"
#include "starboard/shared/gles/gl_call.h"
+#include "third_party/glm/glm/gtc/matrix_transform.hpp"
+#include "third_party/glm/glm/gtc/type_ptr.hpp"
COMPILE_ASSERT(
cobalt::render_tree::kMono == kCbLibVideoStereoModeMono &&
@@ -49,7 +51,11 @@
namespace {
-const float kMaxRenderTargetSize = 15360.0f;
+static const float kMaxRenderTargetSize = 15360.0f;
+
+// The minimum amount of change required in the desired texture size to generate
+// a new offscreen render target for the quad texture.
+static const float kMinTextureSizeEpsilon = 20.0f;
// Matches the signatures of the callback setter functions in exported/video.h
// and exported/graphics.h.
@@ -126,6 +132,16 @@
EndRenderFrame::LazyCallback g_end_render_frame_callback =
LAZY_INSTANCE_INITIALIZER;
+bool ApproxEqual(const cobalt::math::Size& a, const cobalt::math::Size& b,
+ float epsilon) {
+ return std::abs(a.width() - b.width()) < epsilon &&
+ std::abs(a.height() - b.height()) < epsilon;
+}
+
+cobalt::math::Size CobaltSizeFromCbLibSize(CbLibSize size) {
+ return cobalt::math::Size(size.width, size.height);
+}
+
ExternalRasterizer::Impl* g_external_rasterizer_impl = nullptr;
} // namespace
@@ -152,9 +168,18 @@
intptr_t GetMainTextureHandle();
+ // Sets the target size in pixels to use for the main render target buffer.
+ void SetTargetMainTextureSize(const cobalt::math::Size& target_render_size) {
+ target_main_render_target_size_ = target_render_size;
+ }
+
private:
void RenderOffscreenVideo(render_tree::FilterNode* map_to_mesh_filter_node);
+ scoped_refptr<render_tree::MatrixTransformNode> UpdateTextureSizeAndWrapNode(
+ const cobalt::math::Size& native_render_target_size,
+ const scoped_refptr<render_tree::Node>& render_tree);
+
base::ThreadChecker thread_checker_;
backend::GraphicsContextEGL* graphics_context_;
@@ -180,7 +205,11 @@
scoped_refptr<skia::HardwareMesh> left_eye_video_mesh_;
scoped_refptr<skia::HardwareMesh> right_eye_video_mesh_;
render_tree::StereoMode video_stereo_mode_;
- int video_texture_rgb_;
+ GLuint video_texture_rgb_;
+ // The 'target'/'ideal' size to use for the main RenderTarget. The actual size
+ // of the buffer for the main RenderTarget should aim to be within some small
+ // delta of this whenever a new RenderTree is rendered.
+ cobalt::math::Size target_main_render_target_size_;
};
ExternalRasterizer::Impl::Impl(backend::GraphicsContext* graphics_context,
@@ -192,23 +221,23 @@
: graphics_context_(
base::polymorphic_downcast<backend::GraphicsContextEGL*>(
graphics_context)),
- hardware_rasterizer_(
- graphics_context, skia_atlas_width, skia_atlas_height,
- skia_cache_size_in_bytes, scratch_surface_cache_size_in_bytes,
- rasterizer_gpu_cache_size_in_bytes,
- purge_skia_font_caches_on_destruction),
+ hardware_rasterizer_(graphics_context, skia_atlas_width,
+ skia_atlas_height, skia_cache_size_in_bytes,
+ scratch_surface_cache_size_in_bytes,
+ rasterizer_gpu_cache_size_in_bytes,
+ purge_skia_font_caches_on_destruction),
video_projection_type_(kCbLibVideoProjectionTypeNone),
video_stereo_mode_(render_tree::StereoMode::kMono),
- video_texture_rgb_(0) {
+ video_texture_rgb_(0),
+ target_main_render_target_size_(1, 1) {
CHECK(!g_external_rasterizer_impl);
g_external_rasterizer_impl = this;
options_.flags = Rasterizer::kSubmitFlags_Clear;
graphics_context_->MakeCurrent();
- // TODO: Import the correct size for this and any other textures from the lib
- // client and re-generate the size as appropriate.
main_offscreen_render_target_ =
- graphics_context_->CreateOffscreenRenderTarget(math::Size(1920, 1080));
+ graphics_context_->CreateOffscreenRenderTarget(
+ target_main_render_target_size_);
main_texture_.reset(new backend::TextureEGL(
graphics_context_,
make_scoped_refptr(base::polymorphic_downcast<backend::RenderTargetEGL*>(
@@ -321,12 +350,11 @@
}
}
- backend::RenderTargetEGL* main_texture_render_target_egl =
- base::polymorphic_downcast<backend::RenderTargetEGL*>(
- main_offscreen_render_target_.get());
- hardware_rasterizer_.Submit(map_to_mesh_search.replaced_tree,
- main_offscreen_render_target_, options_);
-
+ const scoped_refptr<render_tree::MatrixTransformNode> scaled_main_node =
+ UpdateTextureSizeAndWrapNode(render_target->GetSize(),
+ map_to_mesh_search.replaced_tree);
+ hardware_rasterizer_.Submit(scaled_main_node, main_offscreen_render_target_,
+ options_);
// TODO: Allow clients to specify arbitrary subtrees to render into
// different textures?
g_begin_render_frame_callback.Get().Run();
@@ -334,6 +362,52 @@
g_end_render_frame_callback.Get().Run();
}
+// TODO: Share this logic with the ComponentRenderer.
+scoped_refptr<render_tree::MatrixTransformNode>
+ExternalRasterizer::Impl::UpdateTextureSizeAndWrapNode(
+ const cobalt::math::Size& native_render_target_size,
+ const scoped_refptr<render_tree::Node>& render_tree) {
+ // Create a new offscreen render target if the exist one's size is far enough
+ // off from the target/ideal size.
+ if (!main_offscreen_render_target_ ||
+ !ApproxEqual(main_offscreen_render_target_->GetSize(),
+ target_main_render_target_size_, kMinTextureSizeEpsilon)) {
+ LOG(INFO) << "Creating a new offscreen render target of size "
+ << target_main_render_target_size_;
+ main_offscreen_render_target_ =
+ graphics_context_->CreateOffscreenRenderTarget(
+ target_main_render_target_size_);
+ // Note: The TextureEGL this pointer references must first be destroyed by
+ // calling reset() before a new TextureEGL can be constructed.
+ main_texture_.reset();
+ main_texture_.reset(new backend::TextureEGL(
+ graphics_context_,
+ make_scoped_refptr(
+ base::polymorphic_downcast<backend::RenderTargetEGL*>(
+ main_offscreen_render_target_.get()))));
+ }
+
+ DCHECK(native_render_target_size.width());
+ DCHECK(native_render_target_size.height());
+ // We wrap the RenderTree in a MatrixTransformNode to scale the RenderTree so
+ // that its scale relative to our RenderTarget matches its original scale
+ // relative to native_render_target_size. This makes the texture cropped to
+ // fit our RenderTarget the same amount it would be for the original
+ // RenderTarget.
+ const float texture_x_scale =
+ static_cast<float>(main_offscreen_render_target_->GetSize().width()) /
+ native_render_target_size.width();
+ const float texture_y_scale =
+ static_cast<float>(main_offscreen_render_target_->GetSize().height()) /
+ native_render_target_size.height();
+ const glm::mat3 scale_mat(glm::scale(
+ glm::mat4(1.0f), glm::vec3(texture_x_scale, texture_y_scale, 1)));
+ const cobalt::math::Matrix3F root_transform_matrix =
+ cobalt::math::Matrix3F::FromArray(glm::value_ptr(scale_mat));
+ return scoped_refptr<render_tree::MatrixTransformNode>(
+ new render_tree::MatrixTransformNode(render_tree, root_transform_matrix));
+}
+
render_tree::ResourceProvider* ExternalRasterizer::Impl::GetResourceProvider() {
return hardware_rasterizer_.GetResourceProvider();
}
@@ -504,3 +578,15 @@
return g_external_rasterizer_impl->GetMainTextureHandle();
}
+
+void CbLibGraphicsSetTargetMainTextureSize(
+ const CbLibSize& target_render_size) {
+ DCHECK(g_external_rasterizer_impl);
+ if (!g_external_rasterizer_impl) {
+ LOG(WARNING) << __FUNCTION__
+ << "ExternalRasterizer not yet created; unable to progress.";
+ return;
+ }
+ const cobalt::math::Size size = CobaltSizeFromCbLibSize(target_render_size);
+ g_external_rasterizer_impl->SetTargetMainTextureSize(size);
+}
diff --git a/src/cobalt/renderer/rasterizer/pixel_test.cc b/src/cobalt/renderer/rasterizer/pixel_test.cc
index e62c930..d9a85e7 100644
--- a/src/cobalt/renderer/rasterizer/pixel_test.cc
+++ b/src/cobalt/renderer/rasterizer/pixel_test.cc
@@ -700,6 +700,55 @@
TestTree(new CompositionNode(composition_builder.Pass()));
}
+TEST_F(PixelTest, RectDrawOrder) {
+ // This test ensures that relative draw order is preserved for overlapping
+ // rectangles.
+
+ // Use a linear congruential generator (std::minstd_rand) to generate
+ // deterministic pseudo-random numbers.
+ struct SimpleRand {
+ SimpleRand() : seed(10222016) {}
+ int32_t operator()() {
+ seed = static_cast<int32_t>(
+ (static_cast<int64_t>(seed) * 48271) % 2147483647);
+ return seed;
+ }
+ int32_t seed;
+ } simple_rand;
+
+ const int kPositionScale = 10;
+ math::Size rand_area(output_surface_size().width() / kPositionScale + 1,
+ output_surface_size().height() / kPositionScale + 1);
+
+ // Add a bunch of random rectangles with varying colors and opacity. Limit
+ // opacity to be less than 100% so that previous rectangles are not totally
+ // overwritten. Also leave a gap at the edges of the rectangles so that
+ // adjacent rects are not considered intersecting.
+ CompositionNode::Builder composition_builder;
+ for (int i = 0; i < 400; ++i) {
+ // The evaluation order of function call parameters is not guaranteed.
+ // To maintain determinism, explicitly calculate the parameters before
+ // calling the relevant functions.
+ int x1 = simple_rand() % rand_area.width();
+ int x2 = simple_rand() % rand_area.width();
+ int y1 = simple_rand() % rand_area.height();
+ int y2 = simple_rand() % rand_area.height();
+ float r = (simple_rand() % 256) / 255.0f;
+ float g = (simple_rand() % 256) / 255.0f;
+ float b = (simple_rand() % 256) / 255.0f;
+ float a = (simple_rand() % 5) * 0.1f + 0.1f;
+ composition_builder.AddChild(new RectNode(
+ math::RectF(
+ std::min(x1, x2) * kPositionScale + 0.1f,
+ std::min(y1, y2) * kPositionScale + 0.1f,
+ std::abs(x1 - x2) * kPositionScale - 0.2f,
+ std::abs(y1 - y2) * kPositionScale - 0.2f),
+ scoped_ptr<Brush>(new SolidColorBrush(ColorRGBA(r, g, b, a)))));
+ }
+
+ TestTree(new CompositionNode(composition_builder.Pass()));
+}
+
namespace {
// Creates a texture containing a 3x3 grid of colors each of the provided
diff --git a/src/cobalt/renderer/rasterizer/skia/skia/src/ports/SkTypeface_cobalt.cc b/src/cobalt/renderer/rasterizer/skia/skia/src/ports/SkTypeface_cobalt.cc
index 4ad07b9..ae68696 100644
--- a/src/cobalt/renderer/rasterizer/skia/skia/src/ports/SkTypeface_cobalt.cc
+++ b/src/cobalt/renderer/rasterizer/skia/skia/src/ports/SkTypeface_cobalt.cc
@@ -54,6 +54,10 @@
return stream_->duplicate();
}
+size_t SkTypeface_CobaltStream::GetStreamLength() const {
+ return stream_->getLength();
+}
+
SkTypeface_CobaltStreamProvider::SkTypeface_CobaltStreamProvider(
SkFileMemoryChunkStreamProvider* stream_provider, int face_index,
Style style, bool is_fixed_pitch, const SkString& family_name,
@@ -83,3 +87,11 @@
*face_index = face_index_;
return stream_provider_->OpenStream();
}
+
+size_t SkTypeface_CobaltStreamProvider::GetStreamLength() const {
+ DLOG(WARNING)
+ << "Requesting stream length of SkTypeface_CobaltStreamProvider. "
+ "This requires a file load and should be used sparingly.";
+ SkAutoTUnref<SkFileMemoryChunkStream> stream(stream_provider_->OpenStream());
+ return stream->getLength();
+}
diff --git a/src/cobalt/renderer/rasterizer/skia/skia/src/ports/SkTypeface_cobalt.h b/src/cobalt/renderer/rasterizer/skia/skia/src/ports/SkTypeface_cobalt.h
index 2ac66ab..5e30052 100644
--- a/src/cobalt/renderer/rasterizer/skia/skia/src/ports/SkTypeface_cobalt.h
+++ b/src/cobalt/renderer/rasterizer/skia/skia/src/ports/SkTypeface_cobalt.h
@@ -28,10 +28,12 @@
SkTypeface_Cobalt(int face_index, Style style, bool is_fixed_pitch,
const SkString& family_name);
+ virtual size_t GetStreamLength() const = 0;
+
bool synthesizes_bold() const { return synthesizes_bold_; }
protected:
- virtual void onGetFamilyName(SkString* family_name) const SK_OVERRIDE;
+ void onGetFamilyName(SkString* family_name) const SK_OVERRIDE;
int face_index_;
SkString family_name_;
@@ -46,10 +48,12 @@
SkTypeface_CobaltStream(SkStreamAsset* stream, int face_index, Style style,
bool is_fixed_pitch, const SkString& family_name);
- virtual void onGetFontDescriptor(SkFontDescriptor* descriptor,
- bool* serialize) const SK_OVERRIDE;
+ void onGetFontDescriptor(SkFontDescriptor* descriptor,
+ bool* serialize) const SK_OVERRIDE;
- virtual SkStreamAsset* onOpenStream(int* face_index) const SK_OVERRIDE;
+ SkStreamAsset* onOpenStream(int* face_index) const SK_OVERRIDE;
+
+ size_t GetStreamLength() const SK_OVERRIDE;
private:
typedef SkTypeface_Cobalt INHERITED;
@@ -64,10 +68,12 @@
Style style, bool is_fixed_pitch, const SkString& family_name,
bool disable_synthetic_bolding);
- virtual void onGetFontDescriptor(SkFontDescriptor* descriptor,
- bool* serialize) const SK_OVERRIDE;
+ void onGetFontDescriptor(SkFontDescriptor* descriptor,
+ bool* serialize) const SK_OVERRIDE;
- virtual SkStreamAsset* onOpenStream(int* face_index) const SK_OVERRIDE;
+ SkStreamAsset* onOpenStream(int* face_index) const SK_OVERRIDE;
+
+ size_t GetStreamLength() const SK_OVERRIDE;
private:
typedef SkTypeface_Cobalt INHERITED;
diff --git a/src/cobalt/renderer/rasterizer/skia/typeface.cc b/src/cobalt/renderer/rasterizer/skia/typeface.cc
index e4396fe..6e0866d 100644
--- a/src/cobalt/renderer/rasterizer/skia/typeface.cc
+++ b/src/cobalt/renderer/rasterizer/skia/typeface.cc
@@ -18,12 +18,6 @@
#include "third_party/skia/include/core/SkPaint.h"
-namespace {
-
-const uint32 kEstimatedBytesPerGlyph = 256;
-
-} // namespace
-
namespace cobalt {
namespace renderer {
namespace rasterizer {
@@ -43,7 +37,7 @@
}
uint32 SkiaTypeface::GetEstimatedSizeInBytes() const {
- return typeface_->countGlyphs() * kEstimatedBytesPerGlyph;
+ return static_cast<uint32>(typeface_->GetStreamLength());
}
scoped_refptr<render_tree::Font> SkiaTypeface::CreateFontWithSize(
diff --git a/src/cobalt/renderer/rasterizer/testdata/RectDrawOrder-expected.png b/src/cobalt/renderer/rasterizer/testdata/RectDrawOrder-expected.png
new file mode 100644
index 0000000..bd6f522
--- /dev/null
+++ b/src/cobalt/renderer/rasterizer/testdata/RectDrawOrder-expected.png
Binary files differ
diff --git a/src/cobalt/renderer/submission.h b/src/cobalt/renderer/submission.h
index f9cdd79..8d912f6 100644
--- a/src/cobalt/renderer/submission.h
+++ b/src/cobalt/renderer/submission.h
@@ -60,6 +60,39 @@
// If non-null, |on_rasterized_callback| will be called every time this
// submission is rasterized.
base::Closure on_rasterized_callback;
+
+ // Information about the specific timeline that this submission is intended
+ // to run on. The most important part of TimelineInfo is TimelineInfo::id,
+ // which the renderer pipeline will check to see if it is equal to the
+ // submissions timeline, and if so assume animation continuity. If not, it
+ // will reset its submission queue, and possibly apply any animation playback
+ // configuration changes specified by the other fields in this structure.
+ struct TimelineInfo {
+ // An id of -1 is valid, and acts as the default id.
+ TimelineInfo()
+ : id(-1), allow_latency_reduction(true), max_submission_queue_size(4) {}
+
+ // A number identifying this timeline and used to check for timeline
+ // continuity between submissions. If this changes, the renderer pipeline
+ // will reset its submission queue.
+ int id;
+
+ // If true, allows the vector from renderer time to submission time to
+ // increase over time, in effect reducing latency between when a submission
+ // is submitted to when it appears on the screen. This is typically
+ // desirable for interactive applications, but not as necessary for
+ // non-interactive content (and in this case can result in some frames
+ // being skipped).
+ bool allow_latency_reduction;
+
+ // In order to put a bound on memory we set a maximum submission queue size.
+ // The queue size refers to how many submissions which the renderer has
+ // not caught up to rendering yet will be stored. If latency reduction
+ // is disallowed, this will likely need to be higher to accommodate for
+ // the larger latency between submission and render.
+ int max_submission_queue_size;
+ };
+ TimelineInfo timeline_info;
};
} // namespace renderer
diff --git a/src/cobalt/renderer/submission_queue.cc b/src/cobalt/renderer/submission_queue.cc
index b7b861e..923fc0d 100644
--- a/src/cobalt/renderer/submission_queue.cc
+++ b/src/cobalt/renderer/submission_queue.cc
@@ -34,6 +34,7 @@
SubmissionQueue::SubmissionQueue(
size_t max_queue_size, base::TimeDelta time_to_converge,
+ bool allow_latency_reduction,
const DisposeSubmissionFunction& dispose_function)
: max_queue_size_(max_queue_size),
dispose_function_(dispose_function),
@@ -47,13 +48,16 @@
queue_size_(
"Renderer.SubmissionQueueSize", 0,
"The current size of the renderer submission queue. Each item in "
- "queue contains a render tree and associated animations.") {}
+ "queue contains a render tree and associated animations."),
+ allow_latency_reduction_(allow_latency_reduction) {}
void SubmissionQueue::PushSubmission(const Submission& submission,
const base::TimeTicks& now) {
TRACE_EVENT0("cobalt::renderer", "SubmissionQueue::PushSubmission()");
- CheckThatNowIsMonotonicallyIncreasing(now);
+ if (!submission_queue_.empty()) {
+ CheckThatNowIsMonotonicallyIncreasing(now);
+ }
if (submission_queue_.size() >= max_queue_size_) {
// If we are at capacity, then make room for the new submission by erasing
@@ -78,7 +82,12 @@
double latest_to_submission_time_in_ms =
latest_to_submission_time.InMillisecondsF();
- to_submission_time_in_ms_.SetTarget(latest_to_submission_time_in_ms, now);
+ // Update our mapping from render time to submission time.
+ if (allow_latency_reduction_ || submission_queue_.empty() ||
+ to_submission_time_in_ms_.GetValueAtTime(now) >
+ latest_to_submission_time_in_ms) {
+ to_submission_time_in_ms_.SetTarget(latest_to_submission_time_in_ms, now);
+ }
// Snap time to the new submission if no existing animations are playing both
// currently and during the time that we are snapping to.
diff --git a/src/cobalt/renderer/submission_queue.h b/src/cobalt/renderer/submission_queue.h
index f30a0eb..4ca20ca 100644
--- a/src/cobalt/renderer/submission_queue.h
+++ b/src/cobalt/renderer/submission_queue.h
@@ -105,6 +105,7 @@
// used to allow the Submission/render tree to be disposed/destroyed on a
// separate thread.
SubmissionQueue(size_t max_queue_size, base::TimeDelta time_to_converge,
+ bool allow_latency_reduction = true,
const DisposeSubmissionFunction& dispose_function =
DisposeSubmissionFunction());
@@ -116,19 +117,16 @@
// timing information already setup. Time must be monotonically increasing.
Submission GetCurrentSubmission(const base::TimeTicks& now);
- // Resets the submission queue.
- void Reset() { submission_queue_.clear(); }
-
- private:
- typedef std::list<Submission> SubmissionQueueInternal;
+ // Returns the corresponding submission time for a given TimeTicks
+ // "real world" system value.
+ base::TimeDelta submission_time(const base::TimeTicks& time);
// Returns the corresponding renderer time for a given TimeTicks value
// (e.g. base::TimeTicks::Now()).
base::TimeDelta render_time(const base::TimeTicks& time);
- // Returns the corresponding submission time for a given TimeTicks
- // "real world" system value.
- base::TimeDelta submission_time(const base::TimeTicks& time);
+ private:
+ typedef std::list<Submission> SubmissionQueueInternal;
void PurgeStaleSubmissionsFromQueue(const base::TimeTicks& time);
@@ -168,6 +166,12 @@
base::CVal<base::TimeDelta> to_submission_time_cval_;
base::CVal<size_t> queue_size_;
+
+ // If false, we will only ever allow to_submission_time_cval_ to move
+ // backwards ensuring that animations never speed up during playback (at the
+ // cost of increased and non-recoverable input latency). This is good for
+ // non-interactive content.
+ const bool allow_latency_reduction_;
};
} // namespace renderer
diff --git a/src/cobalt/renderer/submission_queue_test.cc b/src/cobalt/renderer/submission_queue_test.cc
index c3d7a3e..494b131 100644
--- a/src/cobalt/renderer/submission_queue_test.cc
+++ b/src/cobalt/renderer/submission_queue_test.cc
@@ -152,6 +152,53 @@
EXPECT_DOUBLE_EQ(7.5, current.time_offset.InSecondsF());
}
+TEST(SubmissionQueueTest,
+ TimeDoesNotSkewTowardsFasterOffsetsWhenLatencyReductionIsDisabled) {
+ SubmissionQueue queue(4, base::TimeDelta::FromSeconds(1), false);
+
+ Submission first = MakeSubmissionWithUniqueRenderTree(1.0);
+ Submission second = MakeSubmissionWithUniqueRenderTree(5.0);
+
+ // Offset of 1.0 from render tree time.
+ queue.PushSubmission(first, SecondsToTime(2.0));
+ // Offset of 0.5 from render tree time.
+ queue.PushSubmission(second, SecondsToTime(5.5));
+
+ // Check that the first submission has up until this point had its time
+ // advanced at the same rate as the renderer.
+ Submission current = queue.GetCurrentSubmission(SecondsToTime(5.5));
+ EXPECT_EQ(first.render_tree, current.render_tree);
+ EXPECT_DOUBLE_EQ(4.5, current.time_offset.InSecondsF());
+
+ // At this point we are half-way through the transition. Ordinarily the
+ // submission queue would try to transition from the initial offset of 1.0
+ // to the new offset of 0.5, but because latency reduction is disabled, the
+ // offset should never increase and it should stay at 1.0.
+ current = queue.GetCurrentSubmission(SecondsToTime(6.0));
+ EXPECT_EQ(second.render_tree, current.render_tree);
+ EXPECT_NEAR(5, current.time_offset.InSecondsF(), 0.001);
+
+ // After 1 second later, we should still be unchanged from offset 1.0
+ current = queue.GetCurrentSubmission(SecondsToTime(8.0));
+ EXPECT_EQ(second.render_tree, current.render_tree);
+ EXPECT_DOUBLE_EQ(7, current.time_offset.InSecondsF());
+
+ // A third submission that increases the latency should indeed still affect
+ // the submission queue transitioned time.
+ Submission third = MakeSubmissionWithUniqueRenderTree(9.5);
+ queue.PushSubmission(third, SecondsToTime(11.0));
+
+ // Nothing should have changed yet...
+ current = queue.GetCurrentSubmission(SecondsToTime(11.0));
+ EXPECT_EQ(third.render_tree, current.render_tree);
+ EXPECT_NEAR(10, current.time_offset.InSecondsF(), 0.001);
+
+ // We should be transitioning to a larger offset now...
+ current = queue.GetCurrentSubmission(SecondsToTime(11.5));
+ EXPECT_EQ(third.render_tree, current.render_tree);
+ EXPECT_NEAR(10.25, current.time_offset.InSecondsF(), 0.001);
+}
+
// Check that inserting a submission older than what the renderer thinks the
// submission time is will cause the SubmissionQueue to jump back in time to
// make to accomodate the newly pushed old submission.
diff --git a/src/cobalt/script/mozjs-45/mozjs.cc b/src/cobalt/script/mozjs-45/mozjs.cc
index 53edb1f..b17937f 100644
--- a/src/cobalt/script/mozjs-45/mozjs.cc
+++ b/src/cobalt/script/mozjs-45/mozjs.cc
@@ -60,8 +60,7 @@
}
int MozjsMain(int argc, char** argv) {
- JavaScriptEngine::Options js_options;
- cobalt::script::StandaloneJavascriptRunner standalone_runner(js_options);
+ cobalt::script::StandaloneJavascriptRunner standalone_runner();
MozjsGlobalEnvironment* global_environment =
static_cast<MozjsGlobalEnvironment*>(
standalone_runner.global_environment().get());
diff --git a/src/cobalt/script/mozjs-45/mozjs_engine.cc b/src/cobalt/script/mozjs-45/mozjs_engine.cc
index 364d359..f637f47 100644
--- a/src/cobalt/script/mozjs-45/mozjs_engine.cc
+++ b/src/cobalt/script/mozjs-45/mozjs_engine.cc
@@ -142,7 +142,7 @@
: context_(nullptr), accumulated_extra_memory_cost_(0), options_(options) {
TRACE_EVENT0("cobalt::script", "MozjsEngine::MozjsEngine()");
SbOnce(&g_js_init_once_control, CallInitAndRegisterShutDownOnce);
- runtime_ = JS_NewRuntime(options_.js_options.gc_threshold_bytes);
+ runtime_ = JS_NewRuntime(options_.gc_threshold_bytes);
CHECK(runtime_);
// Sets the size of the native stack that should not be exceeded.
@@ -207,7 +207,7 @@
scoped_refptr<GlobalEnvironment> MozjsEngine::CreateGlobalEnvironment() {
TRACE_EVENT0("cobalt::script", "MozjsEngine::CreateGlobalEnvironment()");
DCHECK(thread_checker_.CalledOnValidThread());
- return new MozjsGlobalEnvironment(runtime_, options_.js_options);
+ return new MozjsGlobalEnvironment(runtime_);
}
void MozjsEngine::CollectGarbage() {
@@ -221,7 +221,7 @@
accumulated_extra_memory_cost_ += bytes;
const bool do_collect_garbage =
- accumulated_extra_memory_cost_ > options_.js_options.gc_threshold_bytes;
+ accumulated_extra_memory_cost_ > options_.gc_threshold_bytes;
if (do_collect_garbage) {
accumulated_extra_memory_cost_ = 0;
CollectGarbage();
@@ -326,8 +326,7 @@
scoped_ptr<JavaScriptEngine> JavaScriptEngine::CreateEngine(
const JavaScriptEngine::Options& options) {
TRACE_EVENT0("cobalt::script", "JavaScriptEngine::CreateEngine()");
- mozjs::MozjsEngine::Options moz_options(options);
- return make_scoped_ptr<JavaScriptEngine>(new mozjs::MozjsEngine(moz_options));
+ return make_scoped_ptr<JavaScriptEngine>(new mozjs::MozjsEngine(options));
}
// static
diff --git a/src/cobalt/script/mozjs-45/mozjs_engine.h b/src/cobalt/script/mozjs-45/mozjs_engine.h
index b432000..a4a2314 100644
--- a/src/cobalt/script/mozjs-45/mozjs_engine.h
+++ b/src/cobalt/script/mozjs-45/mozjs_engine.h
@@ -27,12 +27,6 @@
class MozjsEngine : public JavaScriptEngine {
public:
- struct Options {
- explicit Options(const JavaScriptEngine::Options& js_options)
- : js_options(js_options) {}
- JavaScriptEngine::Options js_options; // Generic settings.
- };
-
explicit MozjsEngine(const Options& options);
~MozjsEngine() OVERRIDE;
@@ -70,7 +64,7 @@
// Used to handle javascript errors.
ErrorHandler error_handler_;
- Options options_;
+ JavaScriptEngine::Options options_;
};
} // namespace mozjs
} // namespace script
diff --git a/src/cobalt/script/mozjs-45/mozjs_global_environment.cc b/src/cobalt/script/mozjs-45/mozjs_global_environment.cc
index 086ef37..f551025 100644
--- a/src/cobalt/script/mozjs-45/mozjs_global_environment.cc
+++ b/src/cobalt/script/mozjs-45/mozjs_global_environment.cc
@@ -120,8 +120,7 @@
static base::LazyInstance<MozjsStubHandler> proxy_handler;
} // namespace
-MozjsGlobalEnvironment::MozjsGlobalEnvironment(
- JSRuntime* runtime, const JavaScriptEngine::Options& options)
+MozjsGlobalEnvironment::MozjsGlobalEnvironment(JSRuntime* runtime)
: context_(NULL),
garbage_collection_count_(0),
context_destructor_(&context_),
diff --git a/src/cobalt/script/mozjs-45/mozjs_global_environment.h b/src/cobalt/script/mozjs-45/mozjs_global_environment.h
index a7bccae..ad99d14 100644
--- a/src/cobalt/script/mozjs-45/mozjs_global_environment.h
+++ b/src/cobalt/script/mozjs-45/mozjs_global_environment.h
@@ -45,8 +45,7 @@
class MozjsGlobalEnvironment : public GlobalEnvironment,
public Wrappable::CachedWrapperAccessor {
public:
- MozjsGlobalEnvironment(JSRuntime* runtime,
- const JavaScriptEngine::Options& options);
+ explicit MozjsGlobalEnvironment(JSRuntime* runtime);
~MozjsGlobalEnvironment() OVERRIDE;
void CreateGlobalObject() OVERRIDE;
diff --git a/src/cobalt/script/standalone_javascript_runner.cc b/src/cobalt/script/standalone_javascript_runner.cc
index 528f379..a71d2d1 100644
--- a/src/cobalt/script/standalone_javascript_runner.cc
+++ b/src/cobalt/script/standalone_javascript_runner.cc
@@ -24,8 +24,8 @@
namespace script {
StandaloneJavascriptRunner::StandaloneJavascriptRunner(
- const JavaScriptEngine::Options& options) {
- CommonInitialization(options);
+ const JavaScriptEngine::Options& javascript_engine_options) {
+ CommonInitialization(javascript_engine_options);
global_environment_->CreateGlobalObject();
}
@@ -54,8 +54,8 @@
}
void StandaloneJavascriptRunner::CommonInitialization(
- const JavaScriptEngine::Options& options) {
- engine_ = JavaScriptEngine::CreateEngine(options);
+ const JavaScriptEngine::Options& javascript_engine_options) {
+ engine_ = JavaScriptEngine::CreateEngine(javascript_engine_options);
global_environment_ = engine_->CreateGlobalEnvironment();
environment_settings_.reset(new EnvironmentSettings());
}
diff --git a/src/cobalt/script/standalone_javascript_runner.h b/src/cobalt/script/standalone_javascript_runner.h
index 16526df..a7ffb7b 100644
--- a/src/cobalt/script/standalone_javascript_runner.h
+++ b/src/cobalt/script/standalone_javascript_runner.h
@@ -30,13 +30,14 @@
class StandaloneJavascriptRunner {
public:
StandaloneJavascriptRunner(
- const JavaScriptEngine::Options& options = JavaScriptEngine::Options());
+ const JavaScriptEngine::Options& javascript_engine_options =
+ JavaScriptEngine::Options());
template <typename GlobalInterface>
StandaloneJavascriptRunner(
- const JavaScriptEngine::Options& options,
+ const JavaScriptEngine::Options& javascript_engine_options,
const scoped_refptr<GlobalInterface>& global_object) {
- CommonInitialization(options);
+ CommonInitialization(javascript_engine_options);
global_environment_->CreateGlobalObject(global_object,
environment_settings_.get());
}
@@ -53,7 +54,8 @@
}
private:
- void CommonInitialization(const JavaScriptEngine::Options& options);
+ void CommonInitialization(
+ const JavaScriptEngine::Options& javascript_engine_options);
void ExecuteAndPrintResult(const base::SourceLocation& source_location,
const std::string& script);
diff --git a/src/cobalt/speech/sandbox/speech_sandbox.cc b/src/cobalt/speech/sandbox/speech_sandbox.cc
index 8638535..29b09c5 100644
--- a/src/cobalt/speech/sandbox/speech_sandbox.cc
+++ b/src/cobalt/speech/sandbox/speech_sandbox.cc
@@ -33,7 +33,7 @@
trace_to_file_.reset(new trace_event::ScopedTraceToFile(trace_log_path));
network::NetworkModule::Options network_options;
- network_options.require_https = false;
+ network_options.https_requirement = network::kHTTPSOptional;
network_module_.reset(new network::NetworkModule(network_options));
GURL url(file_path_string);
diff --git a/src/nb/analytics/memory_tracker_helpers.h b/src/nb/analytics/memory_tracker_helpers.h
index 70cf32b..8b846dd 100644
--- a/src/nb/analytics/memory_tracker_helpers.h
+++ b/src/nb/analytics/memory_tracker_helpers.h
@@ -162,7 +162,7 @@
AllocationRecord,
std::less<const void*>, // required, when specifying allocator.
nb::StdAllocator<
- std::pair<const void*, AllocationRecord>,
+ std::pair<const void* const, AllocationRecord>,
NoReportAllocator> > PointerMap;
PointerMap pointer_map_;
diff --git a/src/starboard/CHANGELOG.md b/src/starboard/CHANGELOG.md
index fa69e65..4b010c4 100644
--- a/src/starboard/CHANGELOG.md
+++ b/src/starboard/CHANGELOG.md
@@ -70,6 +70,7 @@
* Color keys
* Closed Caption key
* Application launch key
+ * Channel Up/Down keys
### `kSbEventTypeLowMemory`
diff --git a/src/starboard/client_porting/poem/assert_poem.h b/src/starboard/client_porting/poem/assert_poem.h
index 9d01a43..587d807 100644
--- a/src/starboard/client_porting/poem/assert_poem.h
+++ b/src/starboard/client_porting/poem/assert_poem.h
@@ -23,6 +23,7 @@
#if !defined(POEM_NO_EMULATION)
+#undef assert
// On one line so that the assert macros do not interfere with reporting of line
// numbers in compiler error messages.
#define assert(x) \
diff --git a/src/starboard/client_porting/poem/inet_poem.h b/src/starboard/client_porting/poem/inet_poem.h
index 55cf47a..f575106 100644
--- a/src/starboard/client_porting/poem/inet_poem.h
+++ b/src/starboard/client_porting/poem/inet_poem.h
@@ -19,9 +19,16 @@
#include "starboard/byte_swap.h"
+#undef htonl
#define htonl(x) SB_HOST_TO_NET_U32(x)
+
+#undef htons
#define htons(x) SB_HOST_TO_NET_U16(x)
+
+#undef ntohl
#define ntohl(x) SB_NET_TO_HOST_U32(x)
+
+#undef ntohs
#define ntohs(x) SB_NET_TO_HOST_U16(x)
#endif // STARBOARD_CLIENT_PORTING_POEM_INET_POEM_H_
diff --git a/src/starboard/key.h b/src/starboard/key.h
index 462dcaf..73a1cb6 100644
--- a/src/starboard/key.h
+++ b/src/starboard/key.h
@@ -214,6 +214,8 @@
kSbKeyYellow = 0x195,
kSbKeyBlue = 0x196,
+ kSbKeyChannelUp = 0x1AB,
+ kSbKeyChannelDown = 0x1AC,
kSbKeySubtitle = 0x1CC,
kSbKeyClosedCaption = kSbKeySubtitle,
diff --git a/src/starboard/linux/shared/launcher.py b/src/starboard/linux/shared/launcher.py
index 3b476d1..fa70644 100644
--- a/src/starboard/linux/shared/launcher.py
+++ b/src/starboard/linux/shared/launcher.py
@@ -38,30 +38,26 @@
class Launcher(abstract_launcher.AbstractLauncher):
"""Class for launching Cobalt/tools on Linux."""
- def __init__(self, platform, target_name, config, device_id, args):
+ def __init__(self, platform, target_name, config, device_id, args,
+ output_file, out_directory):
super(Launcher, self).__init__(platform, target_name, config, device_id,
- args)
+ args, output_file, out_directory)
if not self.device_id:
if socket.has_ipv6: # If the device supports IPv6:
self.device_id = "::1" # Use the only IPv6 loopback address
else:
self.device_id = socket.gethostbyname("localhost")
- executable_dir = "{}_{}".format(self.platform, self.config)
- self.executable = os.path.abspath(os.path.join(os.path.dirname(__file__),
- os.pardir, os.pardir,
- os.pardir, "out",
- executable_dir,
- target_name))
+ self.executable = abstract_launcher.GetDefaultTargetPath(
+ platform, config, target_name)
self.pid = None
def Run(self):
"""Runs launcher's executable."""
- signal.signal(signal.SIGTERM, lambda signum, frame: self.Kill())
- signal.signal(signal.SIGINT, lambda signum, frame: self.Kill())
- proc = subprocess.Popen([self.executable] + self.target_command_line_params)
+ proc = subprocess.Popen([self.executable] + self.target_command_line_params,
+ stdout=self.output_file, stderr=self.output_file)
self.pid = proc.pid
proc.wait()
return proc.returncode
@@ -71,5 +67,5 @@
if self.pid:
try:
os.kill(self.pid, signal.SIGTERM)
- except OSError:
+ except OSError: # Process is already dead
raise OSError("Process already closed.")
diff --git a/src/starboard/linux/x64x11/gcc/6.3/compiler_flags.gypi b/src/starboard/linux/x64x11/gcc/6.3/compiler_flags.gypi
index fd25c54..2e7df1d 100644
--- a/src/starboard/linux/x64x11/gcc/6.3/compiler_flags.gypi
+++ b/src/starboard/linux/x64x11/gcc/6.3/compiler_flags.gypi
@@ -70,6 +70,8 @@
'-Wno-unused-local-typedefs',
# Disable warning: 'narrowing conversion'
'-Wno-narrowing',
+ # Do not remove null this checks.
+ '-fno-delete-null-pointer-checks',
],
'conditions': [
['cobalt_fastbuild==0', {
diff --git a/src/starboard/nplb/key_test.cc b/src/starboard/nplb/key_test.cc
index cbfd240..f3644cd 100644
--- a/src/starboard/nplb/key_test.cc
+++ b/src/starboard/nplb/key_test.cc
@@ -30,6 +30,8 @@
EXPECT_NE(kSbKeyUnknown, kSbKeyYellow);
EXPECT_NE(kSbKeyUnknown, kSbKeyBlue);
EXPECT_NE(kSbKeyUnknown, kSbKeySubtitle);
+ EXPECT_NE(kSbKeyUnknown, kSbKeyChannelUp);
+ EXPECT_NE(kSbKeyUnknown, kSbKeyChannelDown);
EXPECT_NE(kSbKeyUnknown, kSbKeyClosedCaption);
EXPECT_NE(kSbKeyUnknown, kSbKeyLaunchThisApplication);
#endif // SB_API_VERSION >= SB_NEW_KEYCODES_API_VERSION
diff --git a/src/starboard/nplb/nplb.gyp b/src/starboard/nplb/nplb.gyp
index eb9b8cd..ec4439d 100644
--- a/src/starboard/nplb/nplb.gyp
+++ b/src/starboard/nplb/nplb.gyp
@@ -249,6 +249,8 @@
'time_zone_get_current_test.cc',
'time_zone_get_dst_name_test.cc',
'time_zone_get_name_test.cc',
+ 'undefined_behavior_test.cc',
+ 'unsafe_math_test.cc',
'user_get_current_test.cc',
'user_get_property_test.cc',
'user_get_signed_in_test.cc',
diff --git a/src/starboard/nplb/undefined_behavior_test.cc b/src/starboard/nplb/undefined_behavior_test.cc
new file mode 100644
index 0000000..8081c3b
--- /dev/null
+++ b/src/starboard/nplb/undefined_behavior_test.cc
@@ -0,0 +1,60 @@
+// Copyright 2017 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace starboard {
+namespace nplb {
+namespace {
+
+class Object {
+ public:
+ SB_C_NOINLINE bool ThisPointerIsNull() {
+ auto* pointer = this;
+ // Intentionally not "return !pointer", and with a side effect for one
+ // branch, in order to more closely match the form that this undefined
+ // behavior is observed to take in the wild.
+ if (!pointer) {
+ return true;
+ }
+ member_ = 42;
+ return false;
+ }
+
+ private:
+ int member_ = 0;
+};
+
+TEST(SbUndefinedBehaviorTest, CallThisPointerIsNullSunnyDay) {
+ auto* object = new Object();
+ EXPECT_FALSE(object->ThisPointerIsNull());
+ delete object;
+}
+
+TEST(SbUndefinedBehaviorTest, CallThisPointerIsNullRainyDay) {
+ auto* object = static_cast<Object*>(nullptr);
+ auto* object_copy = object;
+ EXPECT_TRUE(object_copy->ThisPointerIsNull());
+ // WARNING! Failure of this test indicates that your toolchain believes
+ // that removing a NULL check on a this pointer is a valid optimization.
+ // While from a pure C++ standard perspective this is true, Starboard client
+ // applications, such as Cobalt, depend on third party code bases in which
+ // this assumption is not safe. If you fail this test and are using GCC or
+ // Clang (especially with a GCC version >= 6), then it is highly recommended
+ // that you add the "-fno-delete-null-pointer-checks" flag.
+}
+
+} // namespace
+} // namespace nplb
+} // namespace starboard
diff --git a/src/starboard/nplb/unsafe_math_test.cc b/src/starboard/nplb/unsafe_math_test.cc
new file mode 100644
index 0000000..7eab0cc
--- /dev/null
+++ b/src/starboard/nplb/unsafe_math_test.cc
@@ -0,0 +1,151 @@
+// Copyright 2017 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <cmath>
+#include <limits>
+
+#include "starboard/double.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace starboard {
+namespace nplb {
+namespace {
+
+TEST(SbUnsafeMathTest, NaNDoubleSunnyDay) {
+ auto a = std::numeric_limits<double>::quiet_NaN();
+ auto b = std::numeric_limits<double>::quiet_NaN();
+ auto c = 42.5;
+ auto infinity = std::numeric_limits<double>::infinity();
+
+ // A NaN is a NaN.
+ EXPECT_TRUE(SbDoubleIsNan(a));
+ EXPECT_TRUE(SbDoubleIsNan(b));
+
+ // However, NaN is not ordered. It is not greater than, less than, or
+ // equal to anything, including itself.
+ EXPECT_FALSE(a == a);
+ EXPECT_FALSE(a > a);
+ EXPECT_FALSE(a < a);
+ EXPECT_FALSE(a >= a);
+ EXPECT_FALSE(a <= a);
+
+ EXPECT_FALSE(a == b);
+ EXPECT_FALSE(a > b);
+ EXPECT_FALSE(a < b);
+ EXPECT_FALSE(a >= b);
+ EXPECT_FALSE(a <= b);
+
+ EXPECT_FALSE(a == c);
+ EXPECT_FALSE(a > c);
+ EXPECT_FALSE(a < c);
+ EXPECT_FALSE(a >= c);
+ EXPECT_FALSE(a <= c);
+
+ EXPECT_FALSE(c == a);
+ EXPECT_FALSE(c > a);
+ EXPECT_FALSE(c < a);
+ EXPECT_FALSE(c >= a);
+ EXPECT_FALSE(c <= a);
+
+ // All operations involving a NaN result in a NaN.
+ EXPECT_TRUE(SbDoubleIsNan(a + b));
+ EXPECT_TRUE(SbDoubleIsNan(a * b));
+ EXPECT_TRUE(SbDoubleIsNan(a - b));
+ EXPECT_TRUE(SbDoubleIsNan(a / b));
+
+ EXPECT_TRUE(SbDoubleIsNan(a + c));
+ EXPECT_TRUE(SbDoubleIsNan(a * c));
+ EXPECT_TRUE(SbDoubleIsNan(a - c));
+ EXPECT_TRUE(SbDoubleIsNan(a / c));
+
+ EXPECT_TRUE(SbDoubleIsNan(c + a));
+ EXPECT_TRUE(SbDoubleIsNan(c * a));
+ EXPECT_TRUE(SbDoubleIsNan(c - a));
+ EXPECT_TRUE(SbDoubleIsNan(c / a));
+
+ // (+/- infinity / +/- infinity) results in a NaN.
+ EXPECT_TRUE(SbDoubleIsNan(infinity / infinity));
+ EXPECT_TRUE(SbDoubleIsNan(-infinity / infinity));
+ EXPECT_TRUE(SbDoubleIsNan(infinity / -infinity));
+ EXPECT_TRUE(SbDoubleIsNan(-infinity / -infinity));
+
+ // Infinity minus infinity (and signed equivalents) result in a NaN.
+ EXPECT_TRUE(SbDoubleIsNan(infinity + -infinity));
+ EXPECT_TRUE(SbDoubleIsNan(-infinity + infinity));
+ EXPECT_TRUE(SbDoubleIsNan(infinity - infinity));
+ EXPECT_TRUE(SbDoubleIsNan(-infinity - -infinity));
+
+ EXPECT_TRUE(SbDoubleIsNan(std::sqrt(-c)));
+}
+
+TEST(SbUnsafeMathTest, InfinityDoubleSunnyDay) {
+ auto a = std::numeric_limits<double>::infinity();
+ auto b = std::numeric_limits<double>::infinity();
+
+ // Infinity is equal to itself.
+ EXPECT_TRUE(a == b);
+ EXPECT_TRUE(-a == -b);
+
+ // Infinity is greater than the maximium double.
+ EXPECT_TRUE(a > std::numeric_limits<double>::max());
+ EXPECT_TRUE(a >= std::numeric_limits<double>::max());
+
+ // Negative infinity is less than the minimum double.
+ EXPECT_TRUE(-a < std::numeric_limits<double>::min());
+ EXPECT_TRUE(-a <= std::numeric_limits<double>::min());
+}
+
+TEST(SbUnsafeMathTest, SignedZeroDoubleSunnyDay) {
+ auto a = 42.5;
+ auto positive_zero = 0.0;
+ auto negative_zero = -0.0;
+ auto infinity = std::numeric_limits<double>::infinity();
+
+ EXPECT_TRUE(positive_zero == negative_zero);
+
+ EXPECT_TRUE(negative_zero / a == -positive_zero);
+
+ EXPECT_TRUE(negative_zero * negative_zero == positive_zero);
+
+ EXPECT_TRUE(a + positive_zero == a);
+ EXPECT_TRUE(a + negative_zero == a);
+
+ EXPECT_TRUE(negative_zero + negative_zero == negative_zero - positive_zero);
+ EXPECT_TRUE(negative_zero - positive_zero == negative_zero);
+
+ EXPECT_TRUE(positive_zero + positive_zero == positive_zero - negative_zero);
+ EXPECT_TRUE(positive_zero - negative_zero == positive_zero);
+
+ EXPECT_TRUE(a - a == a + (-a));
+ EXPECT_TRUE(a + (-a) == positive_zero);
+
+ EXPECT_TRUE(std::sqrt(negative_zero) == negative_zero);
+ EXPECT_TRUE(negative_zero / -infinity == positive_zero);
+
+ EXPECT_TRUE(SbDoubleAbsolute(a) / negative_zero == -infinity);
+
+ EXPECT_TRUE(SbDoubleIsNan(positive_zero * infinity));
+ EXPECT_TRUE(SbDoubleIsNan(-positive_zero * infinity));
+ EXPECT_TRUE(SbDoubleIsNan(positive_zero * -infinity));
+ EXPECT_TRUE(SbDoubleIsNan(-positive_zero * -infinity));
+
+ EXPECT_TRUE(SbDoubleIsNan(positive_zero / positive_zero));
+ EXPECT_TRUE(SbDoubleIsNan(-positive_zero / positive_zero));
+ EXPECT_TRUE(SbDoubleIsNan(positive_zero / -positive_zero));
+ EXPECT_TRUE(SbDoubleIsNan(-positive_zero / -positive_zero));
+}
+
+} // namespace
+} // namespace nplb
+} // namespace starboard
diff --git a/src/starboard/raspi/shared/application_dispmanx.cc b/src/starboard/raspi/shared/application_dispmanx.cc
index 4f9dddf..55e6adc 100644
--- a/src/starboard/raspi/shared/application_dispmanx.cc
+++ b/src/starboard/raspi/shared/application_dispmanx.cc
@@ -85,6 +85,7 @@
void ApplicationDispmanx::AcceptFrame(SbPlayer player,
const scoped_refptr<VideoFrame>& frame,
+ int z_index,
int x,
int y,
int width,
diff --git a/src/starboard/raspi/shared/application_dispmanx.h b/src/starboard/raspi/shared/application_dispmanx.h
index a3469c2..37f0b61 100644
--- a/src/starboard/raspi/shared/application_dispmanx.h
+++ b/src/starboard/raspi/shared/application_dispmanx.h
@@ -50,6 +50,7 @@
void Teardown() SB_OVERRIDE;
void AcceptFrame(SbPlayer player,
const scoped_refptr<VideoFrame>& frame,
+ int z_index,
int x,
int y,
int width,
diff --git a/src/starboard/shared/pthread/thread_create.cc b/src/starboard/shared/pthread/thread_create.cc
index 6cc9028..8432041 100644
--- a/src/starboard/shared/pthread/thread_create.cc
+++ b/src/starboard/shared/pthread/thread_create.cc
@@ -61,12 +61,14 @@
delete thread_params;
+#if !SB_HAS_QUIRK(THREAD_AFFINITY_UNSUPPORTED)
if (SbThreadIsValidAffinity(affinity)) {
cpu_set_t cpu_set;
CPU_ZERO(&cpu_set);
CPU_SET(affinity, &cpu_set);
sched_setaffinity(0, sizeof(cpu_set), &cpu_set);
}
+#endif
return entry_point(real_context);
}
diff --git a/src/starboard/shared/starboard/application.cc b/src/starboard/shared/starboard/application.cc
index d287112..71235ab 100644
--- a/src/starboard/shared/starboard/application.cc
+++ b/src/starboard/shared/starboard/application.cc
@@ -156,11 +156,12 @@
#if SB_HAS(PLAYER)
void Application::HandleFrame(SbPlayer player,
const scoped_refptr<VideoFrame>& frame,
+ int z_index,
int x,
int y,
int width,
int height) {
- AcceptFrame(player, frame, x, y, width, height);
+ AcceptFrame(player, frame, z_index, x, y, width, height);
}
#endif // SB_HAS(PLAYER)
diff --git a/src/starboard/shared/starboard/application.h b/src/starboard/shared/starboard/application.h
index d4ec732..df00670 100644
--- a/src/starboard/shared/starboard/application.h
+++ b/src/starboard/shared/starboard/application.h
@@ -228,6 +228,7 @@
// video manually (should be rare). Will be called from an external thread.
void HandleFrame(SbPlayer player,
const scoped_refptr<VideoFrame>& frame,
+ int z_index,
int x,
int y,
int width,
@@ -265,6 +266,7 @@
// system. Will be called from an external thread.
virtual void AcceptFrame(SbPlayer /* player */,
const scoped_refptr<VideoFrame>& /* frame */,
+ int /* z_index */,
int /* x */,
int /* y */,
int /* width */,
diff --git a/src/starboard/shared/starboard/player/filter/filter_based_player_worker_handler.cc b/src/starboard/shared/starboard/player/filter/filter_based_player_worker_handler.cc
index 758f4cb..276c6c5 100644
--- a/src/starboard/shared/starboard/player/filter/filter_based_player_worker_handler.cc
+++ b/src/starboard/shared/starboard/player/filter/filter_based_player_worker_handler.cc
@@ -174,10 +174,16 @@
if (!SbDrmSystemIsValid(drm_system_)) {
return false;
}
- if (drm_system_->Decrypt(input_buffer) == SbDrmSystemPrivate::kRetry) {
+ SbDrmSystemPrivate::DecryptStatus decrypt_status =
+ drm_system_->Decrypt(input_buffer);
+ if (decrypt_status == SbDrmSystemPrivate::kRetry) {
*written = false;
return true;
}
+ if (decrypt_status == SbDrmSystemPrivate::kFailure) {
+ *written = false;
+ return false;
+ }
}
audio_renderer_->WriteSample(input_buffer);
}
@@ -194,10 +200,16 @@
if (!SbDrmSystemIsValid(drm_system_)) {
return false;
}
- if (drm_system_->Decrypt(input_buffer) == SbDrmSystemPrivate::kRetry) {
+ SbDrmSystemPrivate::DecryptStatus decrypt_status =
+ drm_system_->Decrypt(input_buffer);
+ if (decrypt_status == SbDrmSystemPrivate::kRetry) {
*written = false;
return true;
}
+ if (decrypt_status == SbDrmSystemPrivate::kFailure) {
+ *written = false;
+ return false;
+ }
}
video_renderer_->WriteSample(input_buffer);
}
@@ -317,7 +329,8 @@
audio_renderer_->GetCurrentTime(),
audio_renderer_->IsEndOfStreamPlayed());
shared::starboard::Application::Get()->HandleFrame(
- player_, frame, bounds_.x, bounds_.y, bounds_.width, bounds_.height);
+ player_, frame, bounds_.z_index, bounds_.x, bounds_.y, bounds_.width,
+ bounds_.height);
}
player_worker_->UpdateDroppedVideoFrames(
@@ -347,7 +360,7 @@
if (IsPunchoutMode()) {
// Clear the video frame as we terminate.
shared::starboard::Application::Get()->HandleFrame(
- player_, VideoFrame::CreateEOSFrame(), 0, 0, 0, 0);
+ player_, VideoFrame::CreateEOSFrame(), 0, 0, 0, 0, 0);
}
}
diff --git a/src/starboard/shared/starboard/player/player_internal.cc b/src/starboard/shared/starboard/player/player_internal.cc
index 7e017cc..5b8feed 100644
--- a/src/starboard/shared/starboard/player/player_internal.cc
+++ b/src/starboard/shared/starboard/player/player_internal.cc
@@ -90,8 +90,12 @@
worker_->WriteEndOfStream(stream_type);
}
-void SbPlayerPrivate::SetBounds(int x, int y, int width, int height) {
- PlayerWorker::Bounds bounds = {x, y, width, height};
+void SbPlayerPrivate::SetBounds(int z_index,
+ int x,
+ int y,
+ int width,
+ int height) {
+ PlayerWorker::Bounds bounds = {z_index, x, y, width, height};
worker_->SetBounds(bounds);
// TODO: Wait until a frame is rendered with the updated bounds.
}
diff --git a/src/starboard/shared/starboard/player/player_internal.h b/src/starboard/shared/starboard/player/player_internal.h
index 67ce3bb..0a0aa8a 100644
--- a/src/starboard/shared/starboard/player/player_internal.h
+++ b/src/starboard/shared/starboard/player/player_internal.h
@@ -46,7 +46,7 @@
const SbMediaVideoSampleInfo* video_sample_info,
const SbDrmSampleInfo* sample_drm_info);
void WriteEndOfStream(SbMediaType stream_type);
- void SetBounds(int x, int y, int width, int height);
+ void SetBounds(int z_index, int x, int y, int width, int height);
void GetInfo(SbPlayerInfo* out_player_info);
void SetPause(bool pause);
diff --git a/src/starboard/shared/starboard/player/player_set_bounds.cc b/src/starboard/shared/starboard/player/player_set_bounds.cc
index c275c82..0c0921c 100644
--- a/src/starboard/shared/starboard/player/player_set_bounds.cc
+++ b/src/starboard/shared/starboard/player/player_set_bounds.cc
@@ -18,7 +18,7 @@
#include "starboard/shared/starboard/player/player_internal.h"
void SbPlayerSetBounds(SbPlayer player,
- int /*z_index*/,
+ int z_index,
int x,
int y,
int width,
@@ -27,5 +27,5 @@
SB_DLOG(WARNING) << "player is invalid.";
return;
}
- player->SetBounds(x, y, width, height);
+ player->SetBounds(z_index, x, y, width, height);
}
diff --git a/src/starboard/shared/starboard/player/player_worker.h b/src/starboard/shared/starboard/player/player_worker.h
index 30da877..5237fa1 100644
--- a/src/starboard/shared/starboard/player/player_worker.h
+++ b/src/starboard/shared/starboard/player/player_worker.h
@@ -51,6 +51,7 @@
};
struct Bounds {
+ int z_index;
int x;
int y;
int width;
diff --git a/src/starboard/shared/uwp/application_uwp.cc b/src/starboard/shared/uwp/application_uwp.cc
index acc7057..ec9f438 100644
--- a/src/starboard/shared/uwp/application_uwp.cc
+++ b/src/starboard/shared/uwp/application_uwp.cc
@@ -84,6 +84,9 @@
namespace {
+const HdcpProtection kHDCPProtectionMode =
+ HdcpProtection::OnWithTypeEnforcement;
+
const int kWinSockVersionMajor = 2;
const int kWinSockVersionMinor = 2;
@@ -615,7 +618,7 @@
bool ApplicationUwp::IsHdcpOn() {
::starboard::ScopedLock lock(hdcp_session_mutex_);
- return GetHdcpSession()->IsEffectiveProtectionAtLeast(HdcpProtection::On);
+ return GetHdcpSession()->IsEffectiveProtectionAtLeast(kHDCPProtectionMode);
}
bool ApplicationUwp::TurnOnHdcp() {
@@ -623,9 +626,8 @@
{
::starboard::ScopedLock lock(hdcp_session_mutex_);
- protection_result =
- WaitForResult(GetHdcpSession()->SetDesiredMinProtectionAsync(
- HdcpProtection::On));
+ protection_result = WaitForResult(
+ GetHdcpSession()->SetDesiredMinProtectionAsync(kHDCPProtectionMode));
}
if (IsHdcpOn()) {
@@ -660,28 +662,6 @@
return success;
}
-void ApplicationUwp::AcceptFrame(SbPlayer player,
- const scoped_refptr<VideoFrame>& frame,
- int x,
- int y,
- int width,
- int height) {
- SB_UNREFERENCED_PARAMETER(player);
- SB_UNREFERENCED_PARAMETER(frame);
- SB_UNREFERENCED_PARAMETER(x);
- SB_UNREFERENCED_PARAMETER(y);
- SB_UNREFERENCED_PARAMETER(width);
- SB_UNREFERENCED_PARAMETER(height);
-
- if (frame->IsEndOfStream()) {
- // TODO: Implement.
- } else {
- ID3D11Texture2D* dx_texture =
- static_cast<ID3D11Texture2D*>(frame->native_texture());
- SB_UNREFERENCED_PARAMETER(dx_texture);
- }
-}
-
} // namespace uwp
} // namespace shared
} // namespace starboard
diff --git a/src/starboard/shared/uwp/application_uwp.h b/src/starboard/shared/uwp/application_uwp.h
index e62305c..3ded30a 100644
--- a/src/starboard/shared/uwp/application_uwp.h
+++ b/src/starboard/shared/uwp/application_uwp.h
@@ -117,13 +117,6 @@
TimedEvent* GetNextDueTimedEvent() SB_OVERRIDE;
SbTimeMonotonic GetNextTimedEventTargetTime() SB_OVERRIDE;
- void AcceptFrame(SbPlayer player,
- const scoped_refptr<VideoFrame>& frame,
- int x,
- int y,
- int width,
- int height) SB_OVERRIDE;
-
// These two functions should only be called while holding
// |hdcp_session_mutex_|.
Windows::Media::Protection::HdcpSession^ GetHdcpSession();
diff --git a/src/starboard/shared/uwp/system_get_property.cc b/src/starboard/shared/uwp/system_get_property.cc
index 1f4924a..8249fb5 100644
--- a/src/starboard/shared/uwp/system_get_property.cc
+++ b/src/starboard/shared/uwp/system_get_property.cc
@@ -120,7 +120,7 @@
friendly_name = "XboxOne";
} else if (sku == "XBOX_ONE_ED") {
friendly_name = "XboxOne S";
- } else if (sku == "XBOX_ONE_CH") {
+ } else if (sku == "XBOX_ONE_CH" || sku == "XBOX_ONE_SC") {
friendly_name = "XboxOne X";
} else {
friendly_name = "XboxOne " + sku;
diff --git a/src/starboard/shared/x11/application_x11.cc b/src/starboard/shared/x11/application_x11.cc
index c4a5cb6..387cb37 100644
--- a/src/starboard/shared/x11/application_x11.cc
+++ b/src/starboard/shared/x11/application_x11.cc
@@ -696,7 +696,7 @@
wm_delete_atom_(None),
composite_event_id_(kSbEventIdInvalid),
frame_read_index_(0),
- frame_written_(false),
+ frames_updated_(false),
display_(NULL),
paste_buffer_key_release_pending_(false) {
SbAudioSinkPrivate::Initialize();
@@ -754,30 +754,32 @@
if (!windows_.empty()) {
SbWindow window = windows_[0];
if (SbWindowIsValid(window)) {
- int index = -1;
+ std::map<int, FrameInfo> frame_infos;
{
ScopedLock lock(frame_mutex_);
- if (frame_written_) {
- // Clear the old frame, now that we are done with it.
- frame_infos_[frame_read_index_].frame = NULL;
-
+ if (frames_updated_) {
// Increment the index to the next frame, which has been written.
frame_read_index_ = (frame_read_index_ + 1) % kNumFrames;
+ frame_infos.swap(frame_infos_[frame_read_index_]);
// Clear the frame written flag, so we will not advance frames until
// the next frame is written.
- frame_written_ = false;
+ frames_updated_ = false;
}
- index = frame_read_index_;
}
- FrameInfo& frame_info = frame_infos_[frame_read_index_];
+ window->BeginComposite();
+ for (auto& iter : frame_infos) {
+ FrameInfo& frame_info = iter.second;
- if (frame_info.frame && !frame_info.frame->IsEndOfStream() &&
- frame_info.frame->format() != VideoFrame::kBGRA32) {
- frame_info.frame = frame_info.frame->ConvertTo(VideoFrame::kBGRA32);
+ if (frame_info.frame && !frame_info.frame->IsEndOfStream() &&
+ frame_info.frame->format() != VideoFrame::kBGRA32) {
+ frame_info.frame = frame_info.frame->ConvertTo(VideoFrame::kBGRA32);
+ }
+ window->CompositeVideoFrame(frame_info.x, frame_info.y,
+ frame_info.width, frame_info.height,
+ frame_info.frame);
}
- window->Composite(frame_info.x, frame_info.y, frame_info.width,
- frame_info.height, frame_info.frame);
+ window->EndComposite();
}
}
composite_event_id_ =
@@ -786,34 +788,34 @@
void ApplicationX11::AcceptFrame(SbPlayer player,
const scoped_refptr<VideoFrame>& frame,
+ int z_index,
int x,
int y,
int width,
int height) {
- int write_index = -1;
- {
- ScopedLock lock(frame_mutex_);
- // Always write ahead 1 frame of the current read frame.
- write_index = (frame_read_index_ + 1) % kNumFrames;
+ ScopedLock lock(frame_mutex_);
+ // Always write ahead 1 frame of the current read frame.
+ int write_index = (frame_read_index_ + 1) % kNumFrames;
- // Since we are about to modify the next frame, we need to ensure that the
- // reader will not try to advance frames concurrently, so we clear the flag
- // stating the frame has been written.
- frame_written_ = false;
+ for (auto iter = frame_infos_[write_index].begin();
+ iter != frame_infos_[write_index].end(); ++iter) {
+ if (iter->second.player == player) {
+ frame_infos_[write_index].erase(iter);
+ break;
+ }
}
// Copy the frame.
- frame_infos_[write_index].frame = frame;
- frame_infos_[write_index].x = x;
- frame_infos_[write_index].y = y;
- frame_infos_[write_index].width = width;
- frame_infos_[write_index].height = height;
+ FrameInfo& frame_info = frame_infos_[write_index][z_index];
+ frame_info.player = player;
+ frame_info.frame = frame;
+ frame_info.z_index = z_index;
+ frame_info.x = x;
+ frame_info.y = y;
+ frame_info.width = width;
+ frame_info.height = height;
- {
- ScopedLock lock(frame_mutex_);
- // The next frame is now ready to be read.
- frame_written_ = true;
- }
+ frames_updated_ = true;
}
void ApplicationX11::Initialize() {
diff --git a/src/starboard/shared/x11/application_x11.h b/src/starboard/shared/x11/application_x11.h
index cadfc90..48d32d7 100644
--- a/src/starboard/shared/x11/application_x11.h
+++ b/src/starboard/shared/x11/application_x11.h
@@ -17,6 +17,7 @@
#include <X11/Xlib.h>
+#include <map>
#include <queue>
#include <vector>
@@ -52,6 +53,7 @@
protected:
void AcceptFrame(SbPlayer player,
const scoped_refptr<VideoFrame>& frame,
+ int z_index,
int x,
int y,
int width,
@@ -76,7 +78,9 @@
typedef std::vector<SbWindow> SbWindowVector;
struct FrameInfo {
+ SbPlayer player;
scoped_refptr<VideoFrame> frame;
+ int z_index;
int x;
int y;
int width;
@@ -107,9 +111,11 @@
SbEventId composite_event_id_;
Mutex frame_mutex_;
int frame_read_index_;
- bool frame_written_;
+ bool frames_updated_;
+
static const int kNumFrames = 2;
- FrameInfo frame_infos_[kNumFrames];
+ // Video frames from different videos sorted by their z indices.
+ std::map<int, FrameInfo> frame_infos_[kNumFrames];
Display* display_;
SbWindowVector windows_;
diff --git a/src/starboard/shared/x11/window_internal.cc b/src/starboard/shared/x11/window_internal.cc
index a8d42e4..9f4436d 100644
--- a/src/starboard/shared/x11/window_internal.cc
+++ b/src/starboard/shared/x11/window_internal.cc
@@ -140,12 +140,7 @@
XDestroyWindow(display, window);
}
-void SbWindowPrivate::Composite(
- int bounds_x,
- int bounds_y,
- int bounds_width,
- int bounds_height,
- const starboard::scoped_refptr<VideoFrame>& frame) {
+void SbWindowPrivate::BeginComposite() {
XSynchronize(display, True);
XWindowAttributes window_attributes;
XGetWindowAttributes(display, window, &window_attributes);
@@ -174,7 +169,14 @@
XRenderColor black = {0x0000, 0x0000, 0x0000, 0xFFFF};
XRenderFillRectangle(display, PictOpSrc, composition_picture, &black, 0, 0,
width, height);
+}
+void SbWindowPrivate::CompositeVideoFrame(
+ int bounds_x,
+ int bounds_y,
+ int bounds_width,
+ int bounds_height,
+ const starboard::scoped_refptr<VideoFrame>& frame) {
if (frame != NULL && frame->format() == VideoFrame::kBGRA32 &&
frame->GetPlaneCount() > 0 && frame->width() > 0 && frame->height() > 0) {
if (frame->width() != video_pixmap_width ||
@@ -248,7 +250,9 @@
composition_picture, 0, 0, 0, 0, dest_x, dest_y,
video_width, video_height);
}
+}
+void SbWindowPrivate::EndComposite() {
// Composite (with blending) the GL output on top of the composition pixmap
// that already has the current video frame if video is playing.
XRenderComposite(display, PictOpOver, gl_picture, None, composition_picture,
diff --git a/src/starboard/shared/x11/window_internal.h b/src/starboard/shared/x11/window_internal.h
index 6740a9e..7c97758 100644
--- a/src/starboard/shared/x11/window_internal.h
+++ b/src/starboard/shared/x11/window_internal.h
@@ -31,15 +31,19 @@
typedef ::starboard::shared::starboard::player::VideoFrame VideoFrame;
- // Composites graphics and the given video frame video for this window. In
- // kSbPlayerOutputModePunchOut mode, this is the only way any graphics or
- // video is presented in the window. The video frame will be rendered
- // according to boundaries specified by the parameters.
- void Composite(int bounds_x,
- int bounds_y,
- int bounds_width,
- int bounds_height,
- const starboard::scoped_refptr<VideoFrame>& frame);
+ // The following functions composite graphics and the given video frame video
+ // for this window. In kSbPlayerOutputModePunchOut mode, this is the only way
+ // any graphics or video is presented in the window. The video frame will be
+ // rendered according to boundaries specified by the parameters.
+ // CompositeVideoFrame() can be called multiple times in between
+ // BeginComposite() and EndComposite() to display frames from multiple videos.
+ void BeginComposite();
+ void CompositeVideoFrame(int bounds_x,
+ int bounds_y,
+ int bounds_width,
+ int bounds_height,
+ const starboard::scoped_refptr<VideoFrame>& frame);
+ void EndComposite();
// The cached XRender Picture that represents the window that is the
// destination of the composition.
diff --git a/src/starboard/stub/configuration_public.h b/src/starboard/stub/configuration_public.h
index 1336a8f..e7129c6 100644
--- a/src/starboard/stub/configuration_public.h
+++ b/src/starboard/stub/configuration_public.h
@@ -102,6 +102,10 @@
// following quirk.
#undef SB_HAS_QUIRK_DOES_NOT_STACK_ALIGN_OVER_16_BYTES
+// Some platforms do not have thread affinity support. Platforms where this is
+// the case should define the following quirk.
+#undef SB_HAS_QUIRK_THREAD_AFFINITY_UNSUPPORTED
+
// --- System Header Configuration -------------------------------------------
// Any system headers listed here that are not provided by the platform will be
@@ -160,6 +164,15 @@
#define SB_IS_WCHAR_T_SIGNED 1
#endif
+// Some platforms have memset predefined in system headers. Platforms where this
+// is the case should define the following quirk.
+#undef SB_HAS_QUIRK_MEMSET_IN_SYSTEM_HEADERS
+
+// This quirk is used to switch the headers included in
+// starboard/shared/linux/socket_get_interface_address.cc for darwin system
+// headers. It may be removed at some point in favor of a different solution.
+#undef SB_HAS_QUIRK_SOCKET_BSD_HEADERS
+
// --- Compiler Configuration ------------------------------------------------
// The platform's annotation for forcing a C function to be inlined.
diff --git a/src/starboard/tools/abstract_launcher.py b/src/starboard/tools/abstract_launcher.py
index 47e5a69..3f2454b 100644
--- a/src/starboard/tools/abstract_launcher.py
+++ b/src/starboard/tools/abstract_launcher.py
@@ -32,47 +32,107 @@
import starboard.tools.platform as platform_module
-def _GetLauncherForPlatform(platform_path):
+def GetGypModuleForPlatform(platform):
+ """Gets the module containing a platform's GYP configuration.
+
+ Args:
+ platform: Platform on which the app will be run, ex. "linux-x64x11".
+
+ Returns:
+ The module containing the platform's GYP configuration.
+
+ Raises:
+ RuntimeError: The specified platform does not exist.
+ """
+ platform_dict = platform_module.GetAllPorts()
+ if platform in platform_dict:
+ platform_path = platform_dict[platform]
+ if platform_path not in sys.path:
+ sys.path.append(platform_path)
+ gyp_module = importlib.import_module("gyp_configuration")
+ return gyp_module
+ else:
+ raise RuntimeError("Specified platform does not exist.")
+
+
+def _GetLauncherForPlatform(platform):
"""Gets the module containing a platform's concrete launcher implementation.
Args:
- platform_path: Path to the location of a valid starboard platform.
+ platform: Platform on which the app will be run, ex. "linux-x64x11".
Returns:
The module containing the platform's launcher implementation.
"""
- if platform_path not in sys.path:
- sys.path.append(platform_path)
- gyp_module = importlib.import_module("gyp_configuration")
+
+ gyp_module = GetGypModuleForPlatform(platform)
return gyp_module.CreatePlatformConfig().GetLauncher()
-def LauncherFactory(platform, target_name, config, device_id, args):
+def DynamicallyBuildOutDirectory(platform, config):
+ """Constructs the location used to store executable targets/their components.
+
+ Args:
+ platform: The platform to run the executable on, ex. "linux-x64x11".
+ config: The build configuration, ex. "qa".
+
+ Returns:
+ The path to the directory containing executables and/or their components.
+ """
+ path = os.path.abspath(
+ os.path.join(os.path.dirname(__file__),
+ os.pardir, os.pardir, "out",
+ "{}_{}".format(platform, config)))
+ return path
+
+
+def GetDefaultTargetPath(platform, config, target_name):
+ """Constructs the default path to an executable target.
+
+ The default path takes the form of:
+
+ "/path/to/out/<platform>_<config>/target_name"
+
+ Args:
+ platform: The platform to run the executable on, ex. "linux-x64x11".
+ config: The build configuration, ex. "qa".
+ target_name: The name of the executable target, ex. "cobalt"
+
+ Returns:
+ The path to an executable target.
+ """
+ return os.path.join(DynamicallyBuildOutDirectory(platform, config),
+ target_name)
+
+
+def LauncherFactory(platform, target_name, config, device_id, args,
+ output_file=sys.stdout, out_directory=None):
"""Creates the proper launcher based upon command line args.
Args:
- platform: The platform on which the app will run
- target_name: The name of the executable target (ex. "cobalt")
- config: Type of configuration used by the launcher (ex. "qa", "devel")
- device_id: The identifier for the devkit being used
- args: Any extra arguments to be passed on a platform-specific basis
+ platform: The platform on which the app will run.
+ target_name: The name of the executable target (ex. "cobalt").
+ config: Type of configuration used by the launcher (ex. "qa", "devel").
+ device_id: The identifier for the devkit being used.
+ args: Any extra arguments to be passed on a platform-specific basis.
+ output_file: The open file to which the launcher should write its output.
+ out_directory: Path to directory where tool/test targets and/or their
+ components are stored.
Returns:
- An instance of the concrete launcher class for the desired platform
+ An instance of the concrete launcher class for the desired platform.
Raises:
RuntimeError: The platform does not exist, or there is no project root.
"""
+ if not out_directory:
+ out_directory = DynamicallyBuildOutDirectory(platform, config)
+
# Creates launcher for provided platform if the platform has a valid port
- platform_dict = platform_module.GetAllPorts()
- if platform in platform_dict:
- platform_path = platform_dict[platform]
- launcher_module = _GetLauncherForPlatform(platform_path)
- return launcher_module.Launcher(platform, target_name, config, device_id,
- args)
- else:
- raise RuntimeError("Specified platform does not exist.")
+ launcher_module = _GetLauncherForPlatform(platform)
+ return launcher_module.Launcher(platform, target_name, config, device_id,
+ args, output_file, out_directory)
class AbstractLauncher(object):
@@ -80,16 +140,23 @@
__metaclass__ = abc.ABCMeta
- def __init__(self, platform, target_name, config, device_id, args):
+ def __init__(self, platform, target_name, config, device_id,
+ args, output_file, out_directory):
self.platform = platform
self.target_name = target_name
self.config = config
self.device_id = device_id
self.args = args
+ self.out_directory = out_directory
+ self.output_file = output_file
self.target_command_line_params = []
if "target_params" in args:
self.target_command_line_params.extend(args["target_params"])
+ # Launchers that need different startup timeout times should reassign
+ # this variable during initialization.
+ self.startup_timeout_seconds = 2 * 60
+
@abc.abstractmethod
def Run(self):
"""Runs the launcher's executable. Must be implemented in subclasses.
@@ -104,6 +171,10 @@
"""Kills the launcher. Must be implemented in subclasses."""
pass
+ def GetStartupTimeout(self):
+ """Gets the number of seconds to wait before assuming a launcher timeout."""
+ return self.startup_timeout_seconds
+
def GetHostAndPortGivenPort(self, port):
"""Creates a host/port tuple for use on the target device.
diff --git a/src/starboard/tools/command_line.py b/src/starboard/tools/command_line.py
new file mode 100644
index 0000000..0c86290
--- /dev/null
+++ b/src/starboard/tools/command_line.py
@@ -0,0 +1,57 @@
+#!/usr/bin/python
+#
+# Copyright 2017 Google Inc. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+"""Common command line parser for all Starboard tools.
+
+Arguments can be added to the parser returned from CreateParser() on a
+per-tool basis.
+"""
+
+import argparse
+
+
+def CreateParser():
+ """Returns an argparse.ArgumentParser object set up for Starboard tools."""
+ arg_parser = argparse.ArgumentParser(
+ description="Runs application/tool executables.")
+ arg_parser.add_argument(
+ "-p",
+ "--platform",
+ help="Device platform, eg 'linux-x64x11'.")
+ arg_parser.add_argument(
+ "-c",
+ "--config",
+ choices=["debug", "devel", "qa", "gold"],
+ help="Build config (eg, 'qa' or 'devel')")
+ arg_parser.add_argument(
+ "-d",
+ "--device_id",
+ help="Devkit or IP address for the target device.")
+ arg_parser.add_argument(
+ "-t",
+ "--target_name",
+ help="Name of executable target.")
+ arg_parser.add_argument(
+ "--target_params",
+ help="Command line arguments to pass to the executable."
+ " Because different executables could have differing command"
+ " line syntax, list all arguments exactly as you would to the"
+ " executable between a set of double quotation marks.")
+ arg_parser.add_argument(
+ "-o",
+ "--out_directory",
+ help="Directory containing tool binaries or their components."
+ " Automatically derived if absent.")
+ return arg_parser
diff --git a/src/starboard/tools/example/app_launcher_client.py b/src/starboard/tools/example/app_launcher_client.py
index b240697..8df7546 100644
--- a/src/starboard/tools/example/app_launcher_client.py
+++ b/src/starboard/tools/example/app_launcher_client.py
@@ -28,39 +28,13 @@
sys.path.append(env_path)
environment = importlib.import_module("environment")
-import argparse
-
from starboard.tools import abstract_launcher
-
-arg_parser = argparse.ArgumentParser(
- description="Runs application/tool executables.")
-arg_parser.add_argument(
- "-p",
- "--platform",
- help="Device platform, eg 'linux-x64x11'.")
-arg_parser.add_argument(
- "-t",
- "--target_name",
- help="Name of executable.")
-arg_parser.add_argument(
- "-c",
- "--config",
- choices=["debug", "devel", "qa", "gold"],
- help="Build config (eg, 'qa' or 'devel')")
-arg_parser.add_argument(
- "-d",
- "--device_id",
- help="Devkit or IP address for the target device.")
-arg_parser.add_argument(
- "--target_params",
- help="Command line arguments to pass to the executable."
- " Because different executables could have differing command"
- " line syntax, list all arguments exactly as you would to the"
- " executable between a set of double quotation marks.")
+from starboard.tools import command_line
def main():
- args = arg_parser.parse_args()
+ parser = command_line.CreateParser()
+ args = parser.parse_args()
extra_args = {}
if not args.device_id:
@@ -70,9 +44,9 @@
if args.target_params:
extra_args["target_params"] = args.target_params.split(" ")
- launcher = abstract_launcher.LauncherFactory(args.platform,
- args.target_name, args.config,
- args.device_id, extra_args)
+ launcher = abstract_launcher.LauncherFactory(
+ args.platform, args.target_name, args.config,
+ args.device_id, extra_args, out_directory=args.out_directory)
return launcher.Run()
if __name__ == "__main__":
diff --git a/src/starboard/tools/find_private_files.py b/src/starboard/tools/find_private_files.py
index bbb36f4..f9dd9ee 100644
--- a/src/starboard/tools/find_private_files.py
+++ b/src/starboard/tools/find_private_files.py
@@ -1,61 +1,66 @@
-#!/usr/bin/env python
-# Copyright 2017 Google Inc. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http:#www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-'''Gyp helper to find private files if present.
-
-The first argument is the result of "<(DEPTH)" from gyp, the second argument
-is the path/pattern from <(DEPTH)/starboard/private/. Patterns should be given
-using Unix path style '/'.
-
-python find_private_files.py ".." "*.h"
-Would return files matching ../starboard/private/*.h if any exist.
-
-python find_private_files.py ".." "nplb/*_test.cc"
-Would return files matching ../starboard/private/nplb/*_test.cc if any exist.
-
-NOTE: gyp errors often produce no warnings. Be sure to structure usages of this
-script by gyp files like the line below, where the'<!@' is a gyp command
-expansion that will process the results into a list of returned file paths.
-Quoting arguments protects against wildcard expansion and other undesirable
-gyp/shell behavior.
-'<!@(python "<(DEPTH)/starboard/tools/find_private_files.py" "<(DEPTH)" "*.h")',
-'''
-
-import glob
-import os
-import sys
-
-_PRIVATE_DIR_PATH = 'starboard/private'
-
-def find_private_files(depth, target_pattern):
- '''Assembles search glob and finds files matching the target pattern.
-
- Args:
- depth: The string result of "<(DEPTH)"" from gyp.
- target_pattern: The string path/pattern from <(DEPTH)/starboard/private/.
- '''
- path = os.path.normpath(os.path.join(
- depth, _PRIVATE_DIR_PATH, target_pattern))
- for f in glob.iglob(path):
- # Switch to Unix style '/' for gyp.
- print f.replace('\\', '/')
-
-
-if __name__ == '__main__':
- depth_arg = sys.argv[1]
- target_pattern_arg = sys.argv[2]
-
- find_private_files(depth_arg, target_pattern_arg)
-
- sys.exit(0)
+#!/usr/bin/env python
+# Copyright 2017 Google Inc. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http:#www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+"""Gyp helper to find private files if present.
+
+The first argument is the result of "<(DEPTH)" from gyp, the second argument
+is the path/pattern from <(DEPTH)/starboard/private/. Patterns should be given
+using Unix path style '/'.
+
+python find_private_files.py "../.." "*.h"
+Would return files matching ../../starboard/private/*.h if any exist.
+
+python find_private_files.py "../.." "nplb/*_test.cc"
+Would return files matching ../../starboard/private/nplb/*_test.cc if any exist.
+
+NOTE: gyp errors often produce no warnings. Be sure to structure usages of this
+script by gyp files like the line below, where the'<!@' is a gyp command
+expansion that will process the results into a list of returned file paths.
+Quoting arguments protects against wildcard expansion and other undesirable
+gyp/shell behavior.
+'<!@(python "<(DEPTH)/starboard/tools/find_private_files.py" "<(DEPTH)" "*.h")',
+"""
+
+import glob
+import os
+import sys
+
+
+def find_private_files(depth,
+ target_pattern,
+ private_dir_path='starboard/private'):
+ """Assembles search glob and finds files matching the target pattern.
+
+ Args:
+ depth: The string result of "<(DEPTH)"" from gyp.
+ target_pattern: The string path/pattern from <(DEPTH)/|private_dir_path|
+ private_dir_path: Optional The path to the private directory, which
+ defaults to 'starboard/private'.
+ """
+ path = os.path.normpath(os.path.join(depth, private_dir_path, target_pattern))
+ for f in glob.iglob(path):
+ # Switch to Unix style '/' for gyp.
+ print f.replace('\\', '/')
+
+
+if __name__ == '__main__':
+ depth_arg = sys.argv[1]
+ target_pattern_arg = sys.argv[2]
+ if len(sys.argv) > 3:
+ private_dir_path_arg = sys.argv[3]
+ find_private_files(depth_arg, target_pattern_arg, private_dir_path_arg)
+ else:
+ find_private_files(depth_arg, target_pattern_arg)
+
+ sys.exit(0)
diff --git a/src/starboard/tools/toolchain/abstract.py b/src/starboard/tools/toolchain/abstract.py
index c1d940b..3f9f3d3 100644
--- a/src/starboard/tools/toolchain/abstract.py
+++ b/src/starboard/tools/toolchain/abstract.py
@@ -213,6 +213,35 @@
"""
pass
+class ObjectiveCxxCompiler(Tool):
+ """Compiles Objective-C++ sources."""
+
+ def IsPlatformAgnostic(self):
+ return False
+
+ def GetRuleName(self):
+ return 'compile_objective_cxx'
+
+ @abc.abstractmethod
+ def GetFlags(self, defines, include_dirs, cflags):
+ """Returns tool flags specific to a target.
+
+ This method translates platform-agnostic concepts into a command line
+ arguments understood by a tool.
+
+ Args:
+ defines: A list of preprocessor defines in "NAME=VALUE" format.
+ include_dirs: A list of header search directories.
+ cflags: A list of GCC-style command-line flags. See
+ https://gcc.gnu.org/onlinedocs/gcc/Invoking-GCC.html#Invoking-GCC for
+ details.
+
+ Returns:
+ A list of unquoted strings, one for each flag. It is a responsibility of a
+ caller to quote flags that contain special characters (as determined by a
+ shell) before passing to a tool.
+ """
+ pass
class AssemblerWithCPreprocessor(Tool):
"""Compiles assembler sources that contain C preprocessor directives."""
diff --git a/src/starboard/tools/toolchain/clang.py b/src/starboard/tools/toolchain/clang.py
index 68bedf1..1cf467f 100644
--- a/src/starboard/tools/toolchain/clang.py
+++ b/src/starboard/tools/toolchain/clang.py
@@ -90,6 +90,26 @@
]
return define_flags + include_dir_flags + cflags
+class ObjectiveCxxCompiler(CompilerBase, abstract.ObjectiveCxxCompiler):
+ """Compiles Objective-C++ sources using Clang."""
+
+ def __init__(self, **kwargs):
+ super(ObjectiveCxxCompiler, self).__init__(**kwargs)
+
+ def GetCommand(self, path, extra_flags, flags):
+ return '{0} -x objective-c++ -MMD -MF $out.d {1} {2} -c $in -o $out'.format(
+ path, extra_flags, flags)
+
+ def GetDescription(self):
+ return 'OBJCXX $out'
+
+ def GetFlags(self, defines, include_dirs, cflags):
+ define_flags = ['-D{0}'.format(define) for define in defines]
+ include_dir_flags = [
+ '-I{0}'.format(include_dir) for include_dir in include_dirs
+ ]
+ return define_flags + include_dir_flags + cflags
+
class AssemblerWithCPreprocessor(CompilerBase,
abstract.AssemblerWithCPreprocessor):
diff --git a/src/starboard/win/lib/gyp_configuration.gypi b/src/starboard/win/lib/gyp_configuration.gypi
deleted file mode 100644
index 9a3622e..0000000
--- a/src/starboard/win/lib/gyp_configuration.gypi
+++ /dev/null
@@ -1,52 +0,0 @@
-# Copyright 2017 Google Inc. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-{
- 'variables': {
- 'javascript_engine': 'mozjs-45',
- 'cobalt_enable_jit': 0,
- # TODO: In theory, there are tools that can combine static libraries into
- # thick static libraries with all their transitive dependencies. Using
- # shared_library here can have unexpected consequences. Explore building
- # this into a thick static library instead.
- 'final_executable_type': 'shared_library',
- 'default_renderer_options_dependency': '<(DEPTH)/cobalt/renderer/rasterizer/lib/lib.gyp:external_rasterizer',
- 'sb_enable_lib': 1,
- 'enable_map_to_mesh': 1,
- 'angle_build_winrt': 0,
- 'winrt': 0,
- 'enable_d3d11_feature_level_11': 1,
- },
- 'includes': [
- '../shared/gyp_configuration.gypi',
- ],
- 'target_defaults': {
- 'default_configuration': 'win-lib_debug',
- 'configurations': {
-
- 'win-lib_debug': {
- 'inherit_from': ['win32_base', 'msvs_debug'],
- },
- 'win-lib_devel': {
- 'inherit_from': ['win32_base', 'msvs_devel'],
- },
- 'win-lib_qa': {
- 'inherit_from': ['win32_base', 'msvs_qa'],
- },
- 'win-lib_gold': {
- 'inherit_from': ['win32_base', 'msvs_gold'],
- },
- }, # end of configurations
- },
-}
diff --git a/src/starboard/win/lib/starboard_platform.gyp b/src/starboard/win/lib/starboard_platform.gyp
deleted file mode 100644
index 986d8b6..0000000
--- a/src/starboard/win/lib/starboard_platform.gyp
+++ /dev/null
@@ -1,41 +0,0 @@
-# Copyright 2017 Google Inc. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-{
- 'includes': [
- '../shared/starboard_platform.gypi',
- ],
- 'variables': {
- 'starboard_platform_dependent_files': [
- 'atomic_public.h',
- 'configuration_public.h',
- 'thread_types_public.h',
- '../shared/system_get_path.cc',
- '<(DEPTH)/starboard/shared/starboard/localized_strings.cc',
- '<(DEPTH)/starboard/shared/starboard/localized_strings.cc',
- '<(DEPTH)/starboard/shared/starboard/queue_application.cc',
- '<(DEPTH)/starboard/shared/starboard/system_request_pause.cc',
- '<(DEPTH)/starboard/shared/starboard/system_request_pause.cc',
- '<(DEPTH)/starboard/shared/starboard/system_request_stop.cc',
- '<(DEPTH)/starboard/shared/starboard/system_request_stop.cc',
- '<(DEPTH)/starboard/shared/starboard/system_request_suspend.cc',
- '<(DEPTH)/starboard/shared/starboard/system_request_suspend.cc',
- '<(DEPTH)/starboard/shared/starboard/system_request_unpause.cc',
- '<(DEPTH)/starboard/shared/starboard/system_request_unpause.cc',
- '<@(uwp_incompatible_win32)',
- '<@(win32_media_player_files)',
- '<@(win32_shared_drm_files)',
- '<@(win32_shared_media_player_files)',
- ],
- },
-}
diff --git a/src/starboard/win/win32/lib/gyp_configuration.gypi b/src/starboard/win/win32/lib/gyp_configuration.gypi
index 7d8ddb2..426c515 100644
--- a/src/starboard/win/win32/lib/gyp_configuration.gypi
+++ b/src/starboard/win/win32/lib/gyp_configuration.gypi
@@ -14,7 +14,7 @@
{
'variables': {
- 'javascript_engine': 'mozjs',
+ 'javascript_engine': 'mozjs-45',
'cobalt_enable_jit': 0,
# TODO: In theory, there are tools that can combine static libraries into
# thick static libraries with all their transitive dependencies. Using
@@ -23,6 +23,7 @@
'final_executable_type': 'shared_library',
'default_renderer_options_dependency': '<(DEPTH)/cobalt/renderer/rasterizer/lib/lib.gyp:external_rasterizer',
'sb_enable_lib': 1,
+ 'enable_map_to_mesh': 1,
'angle_build_winrt': 0,
'winrt': 0,
'enable_d3d11_feature_level_11': 1,
diff --git a/src/third_party/libevent/kqueue.c b/src/third_party/libevent/kqueue.c
index bcad213..9f9e671 100644
--- a/src/third_party/libevent/kqueue.c
+++ b/src/third_party/libevent/kqueue.c
@@ -92,7 +92,9 @@
struct kevent *changes;
int nchanges;
struct kevent *events;
+#ifndef STARBOARD
struct event_list evsigevents[NSIG];
+#endif
int nevents;
int kq;
pid_t pid;
@@ -129,7 +131,7 @@
return (NULL);
/* Initalize the kernel queue */
-
+
if ((kq = kqueue()) == -1) {
event_warn("kqueue");
free (kqueueop);
@@ -154,16 +156,18 @@
}
kqueueop->nevents = NEVENT;
+#ifndef STARBOARD
/* we need to keep track of multiple events per signal */
for (i = 0; i < NSIG; ++i) {
TAILQ_INIT(&kqueueop->evsigevents[i]);
}
+#endif
/* Check for Mac OS X kqueue bug. */
kqueueop->changes[0].ident = -1;
kqueueop->changes[0].filter = EVFILT_READ;
kqueueop->changes[0].flags = EV_ADD;
- /*
+ /*
* If kqueue works, then kevent will succeed, and it will
* stick an error in events[0]. If kqueue is broken, then
* kevent will fail.
@@ -222,7 +226,7 @@
memcpy(&kqop->changes[kqop->nchanges++], kev, sizeof(struct kevent));
event_debug(("%s: fd %d %s%s",
- __func__, (int)kev->ident,
+ __func__, (int)kev->ident,
kev->filter == EVFILT_READ ? "EVFILT_READ" : "EVFILT_WRITE",
kev->flags == EV_DELETE ? " (del)" : ""));
@@ -267,7 +271,7 @@
int which = 0;
if (events[i].flags & EV_ERROR) {
- /*
+ /*
* Error messages that can happen, when a delete fails.
* EBADF happens when the file discriptor has been
* closed,
@@ -324,25 +328,26 @@
struct kqop *kqop = arg;
struct kevent kev;
+#ifndef STARBOARD
if (ev->ev_events & EV_SIGNAL) {
int nsignal = EVENT_SIGNAL(ev);
assert(nsignal >= 0 && nsignal < NSIG);
if (TAILQ_EMPTY(&kqop->evsigevents[nsignal])) {
struct timespec timeout = { 0, 0 };
-
+
memset(&kev, 0, sizeof(kev));
kev.ident = nsignal;
kev.filter = EVFILT_SIGNAL;
kev.flags = EV_ADD;
kev.udata = PTR_TO_UDATA(&kqop->evsigevents[nsignal]);
-
+
/* Be ready for the signal if it is sent any
* time between now and the next call to
* kq_dispatch. */
if (kevent(kqop->kq, &kev, 1, NULL, 0, &timeout) == -1)
return (-1);
-
+
if (_evsignal_set_handler(ev->ev_base, nsignal,
kq_sighandler) == -1)
return (-1);
@@ -353,6 +358,7 @@
ev->ev_flags |= EVLIST_X_KQINKERNEL;
return (0);
}
+#endif
if (ev->ev_events & EV_READ) {
memset(&kev, 0, sizeof(kev));
@@ -366,7 +372,7 @@
if (!(ev->ev_events & EV_PERSIST))
kev.flags |= EV_ONESHOT;
kev.udata = PTR_TO_UDATA(ev);
-
+
if (kq_insert(kqop, &kev) == -1)
return (-1);
@@ -381,7 +387,7 @@
if (!(ev->ev_events & EV_PERSIST))
kev.flags |= EV_ONESHOT;
kev.udata = PTR_TO_UDATA(ev);
-
+
if (kq_insert(kqop, &kev) == -1)
return (-1);
@@ -400,6 +406,7 @@
if (!(ev->ev_flags & EVLIST_X_KQINKERNEL))
return (0);
+#ifndef STARBOARD
if (ev->ev_events & EV_SIGNAL) {
int nsignal = EVENT_SIGNAL(ev);
struct timespec timeout = { 0, 0 };
@@ -411,7 +418,7 @@
kev.ident = nsignal;
kev.filter = EVFILT_SIGNAL;
kev.flags = EV_DELETE;
-
+
/* Because we insert signal events
* immediately, we need to delete them
* immediately, too */
@@ -426,13 +433,14 @@
ev->ev_flags &= ~EVLIST_X_KQINKERNEL;
return (0);
}
+#endif
if (ev->ev_events & EV_READ) {
memset(&kev, 0, sizeof(kev));
kev.ident = ev->ev_fd;
kev.filter = EVFILT_READ;
kev.flags = EV_DELETE;
-
+
if (kq_insert(kqop, &kev) == -1)
return (-1);
@@ -444,7 +452,7 @@
kev.ident = ev->ev_fd;
kev.filter = EVFILT_WRITE;
kev.flags = EV_DELETE;
-
+
if (kq_insert(kqop, &kev) == -1)
return (-1);
diff --git a/src/third_party/libevent/libevent.gyp b/src/third_party/libevent/libevent.gyp
index d62a6c9..612fdc2 100644
--- a/src/third_party/libevent/libevent.gyp
+++ b/src/third_party/libevent/libevent.gyp
@@ -87,7 +87,7 @@
'include_dirs': [ 'starboard/linux' ],
}
],
- [ 'target_os == "ios"', {
+ [ 'target_os in ("tvos", "ios", "mac")', {
'include_dirs': [ 'starboard/darwin' ],
}
],
diff --git a/src/third_party/libwebp/libwebp.gyp b/src/third_party/libwebp/libwebp.gyp
index 9b659e9..f2a17f3 100644
--- a/src/third_party/libwebp/libwebp.gyp
+++ b/src/third_party/libwebp/libwebp.gyp
@@ -73,8 +73,9 @@
},{ # "target_arch != "arm" or arm_version < 7"
'type': 'none',
}],
- ['target_arch == "arm" and arm_version >= 8 and clang == 1', {
- # NEON is implicit on ARMv8, and clang doesn't like the redundant flag
+ ['target_arch == "arm" and arm_version >= 8', {
+ # NEON is implicit on ARMv8, and both clang and gcc don't like the
+ # redundant flag.
'cflags!': [ '-mfpu=neon' ],
}],
],
diff --git a/src/third_party/protobuf/src/google/protobuf/stubs/atomicops.h b/src/third_party/protobuf/src/google/protobuf/stubs/atomicops.h
index b84117b..1447a97 100644
--- a/src/third_party/protobuf/src/google/protobuf/stubs/atomicops.h
+++ b/src/third_party/protobuf/src/google/protobuf/stubs/atomicops.h
@@ -100,7 +100,15 @@
// Use AtomicWord for a machine-sized pointer. It will use the Atomic32 or
// Atomic64 routines below, depending on your architecture.
+#if defined(STARBOARD)
+#if SB_HAS(64_BIT_POINTERS)
+typedef SbAtomic64 AtomicWord;
+#else
+typedef SbAtomic32 AtomicWord;
+#endif
+#else
typedef intptr_t AtomicWord;
+#endif
// Atomically execute:
// result = *ptr;
diff --git a/src/third_party/protobuf/src/google/protobuf/stubs/port.h b/src/third_party/protobuf/src/google/protobuf/stubs/port.h
index d6189dc..e751fb1 100644
--- a/src/third_party/protobuf/src/google/protobuf/stubs/port.h
+++ b/src/third_party/protobuf/src/google/protobuf/stubs/port.h
@@ -51,6 +51,15 @@
// This workaround is for protoc auto-generated files which use memset.
#ifndef memset
#define memset SbMemorySet
+#if SB_HAS_QUIRK(MEMSET_IN_SYSTEM_HEADERS)
+ namespace std {
+ inline namespace __1 {
+ void *SbMemorySet(void* destination, int byte_value, size_t count) {
+ return ::SbMemorySet(destination, byte_value, count);
+ }
+ }
+ }
+#endif // SB_HAS_QUIRK(MEMSET_IN_SYSTEM_HEADERS)
#endif // memset
#endif
diff --git a/src/third_party/sqlite/amalgamation/sqlite3.c b/src/third_party/sqlite/amalgamation/sqlite3.c
index f89fabc..e7f4e39 100644
--- a/src/third_party/sqlite/amalgamation/sqlite3.c
+++ b/src/third_party/sqlite/amalgamation/sqlite3.c
@@ -1,3 +1,7 @@
+// TODO: Undefine this globally in
+// starboard/darwin/tvos/simulator/gyp_configuration.gypi
+#undef __APPLE__
+
/******************************************************************************
** This file is an amalgamation of many separate C source files from SQLite
** version 3.7.6.3. By combining all the individual C code files into this
diff --git a/src/tools/gyp/pylib/gyp/generator/ninja.py b/src/tools/gyp/pylib/gyp/generator/ninja.py
index 1724d6f..9f75af1 100755
--- a/src/tools/gyp/pylib/gyp/generator/ninja.py
+++ b/src/tools/gyp/pylib/gyp/generator/ninja.py
@@ -913,6 +913,7 @@
cflags = GetConfigFlags(config, self.toolset, 'cflags')
cflags_c = GetConfigFlags(config, self.toolset, 'cflags_c')
cflags_cc = GetConfigFlags(config, self.toolset, 'cflags_cc')
+ cflags_mm = GetConfigFlags(config, self.toolset, 'cflags_mm')
c_compiler = FindFirstInstanceOf(abstract.CCompiler, toolchain)
if c_compiler:
@@ -930,6 +931,16 @@
'{0}_flags'.format(GetNinjaRuleName(cxx_compiler, self.toolset)),
JoinShellArguments(shell, cxx_compiler_flags))
+ objcxx_compiler = FindFirstInstanceOf(abstract.ObjectiveCxxCompiler,
+ toolchain)
+ if objcxx_compiler:
+ objcxx_compiler_flags = objcxx_compiler.GetFlags(defines, include_dirs,
+ cflags + cflags_cc +
+ cflags_mm)
+ self.ninja.variable(
+ '{0}_flags'.format(GetNinjaRuleName(objcxx_compiler, self.toolset)),
+ JoinShellArguments(shell, objcxx_compiler_flags))
+
assembler = FindFirstInstanceOf(abstract.AssemblerWithCPreprocessor,
toolchain)
if assembler:
@@ -954,6 +965,11 @@
'to build {0} for {1} platform.').format(
source, self.toolset)
rule_name = GetNinjaRuleName(cxx_compiler, self.toolset)
+ elif extension in ['.mm']:
+ assert objcxx_compiler, ('Toolchain must provide Objective-C++ '
+ 'compiler in order to build {0} for {1} '
+ 'platform.').format(source, self.toolset)
+ rule_name = GetNinjaRuleName(objcxx_compiler, self.toolset)
elif extension in ['.S', '.s']:
assert assembler, ('Toolchain must provide assembler in order to '
'build {0} for {1} platform.').format(
@@ -1192,7 +1208,8 @@
self.ninja.variable('{0}_flags'.format(rule_name),
JoinShellArguments(shell, executable_linker_flags))
else:
- raise Exception('Target type {0} is not supported.'.format(target_type))
+ raise Exception('Target type {0} is not supported for target {1}.'
+ .format(target_type, spec['target_name']))
order_only_deps = set()