Import Cobalt 2.10060 2016-08-29
diff --git a/codereview.settings b/codereview.settings
new file mode 100644
index 0000000..1950c32
--- /dev/null
+++ b/codereview.settings
@@ -0,0 +1,3 @@
+GERRIT_HOST: cobalt-review.googlesource.com
+GERRIT_AUTODETECT_BRANCH: true
+CODE_REVIEW_SERVER: cobalt-review.googlesource.com
diff --git a/src/CONTRIBUTING.md b/src/CONTRIBUTING.md
new file mode 100644
index 0000000..bd99ed6
--- /dev/null
+++ b/src/CONTRIBUTING.md
@@ -0,0 +1,62 @@
+# Contributing to Cobalt
+
+We'd love to hear about how you would like to contribute to Cobalt! It's worth
+reading through this modest document first, to understand the process and to
+make sure you know what to expect.
+
+
+## Before You Contribute
+
+### As an Individual
+
+Before Cobalt can use your code, as an unaffiliated individual, you must sign
+the [Google Individual Contributor License Agreement](https://cla.developers.google.com/about/google-individual) (CLA), which you can do online.
+
+### As a Company
+
+If you are a company that wishes to have one or more employees contribute to
+Cobalt on-the-clock, that is covered by a different agreement, the
+[Software Grant and Corporate Contributor License Agreement](https://cla.developers.google.com/about/google-corporate).
+
+### What is a CLA?
+
+The Contributor License Agreement is necessary mainly because you own the
+copyright to your changes, even after your contribution becomes part of our
+codebase, so we need your permission to use and distribute your code. We also
+need to be sure of various other things — for instance that you'll tell us if
+you know that your code infringes on other people's patents. You don't have to
+sign the CLA until after you've submitted your code for review and a member has
+approved it, but you must do it before we can put your code into our codebase.
+Before you start working on a larger contribution, you should get in touch with
+us first with your idea so that we can help out and possibly guide
+you. Coordinating up front makes it much easier to avoid frustration later on.
+
+
+### Code Reviews
+
+All submissions, including submissions by project members, require review. We
+currently use [Gerrit Code Review](https://www.gerritcodereview.com/) for this
+purpose. Currently, team-member submissions go through private reviews, and
+external submissions go through public reviews.
+
+
+## Submission Process
+
+We admit that this submission process is currently not completely optimized to
+make contributions easy, and we hope to make improvements to it in the
+future. It will always include some form of signing the CLA and submitting the
+code for review before merging changes into the Cobalt master tree.
+
+ 1. Ensure you or your company have signed the appropriate CLA (see "Before You
+ Contribute" above).
+ 1. Rebase your changes down into a single git commit.
+ 1. Run `git cl upload` to upload the review to
+ [Cobalt's Gerrit instance](https://cobalt-review.googlesource.com/).
+ 1. Someone from the maintainers team will review the code, putting up comments
+ on any things that need to change for submission.
+ 1. If you need to make changes, make them locally, test them, then `git commit
+ --amend` to add them to the *existing* commit. Then return to step 2.
+ 1. If you do not need to make any more changes, a maintainer will integrate
+ the change into our private repository, and it will get pushed out to the
+ public repository after some time.
+
diff --git a/src/README.cobalt.txt b/src/README.cobalt.txt
deleted file mode 100644
index bc2d9c7..0000000
--- a/src/README.cobalt.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-This is a fork of the chromium repository at http://git.chromium.org/git/chromium.git
-
diff --git a/src/README.md b/src/README.md
index fb912c9..025610b 100644
--- a/src/README.md
+++ b/src/README.md
@@ -241,12 +241,12 @@
optimized, with the most debug information at the top (debug) to the fastest,
most optimized, and with the least debug information at the bottom (gold):
- | Type | Optimizations | Logging | Asserts | Debug Info | Console |
- | :---- | :------------ | :------ | :------ | :--------- | :------- |
- | debug | None | Full | Full | Full | Enabled |
- | devel | Full | Full | Full | Full | Enabled |
- | qa | Full | Limited | None | None | Enabled |
- | gold | Full | None | None | None | Disabled |
+ Type | Optimizations | Logging | Asserts | Debug Info | Console
+ :---- | :------------ | :------ | :------ | :--------- | :-------
+ debug | None | Full | Full | Full | Enabled
+ devel | Full | Full | Full | Full | Enabled
+ qa | Full | Limited | None | None | Enabled
+ gold | Full | None | None | None | Disabled
When building for release, you should always use a gold build for the final
product.
@@ -254,3 +254,9 @@
$ cobalt/build/gyp_cobalt -C gold linux-x64x11
$ ninja -C out/linux-x64x11_gold cobalt
$ out/linux-x64x11_gold/cobalt
+
+
+## Origin of this Repository
+
+This is a fork of the chromium repository at http://git.chromium.org/git/chromium.git
+
diff --git a/src/base/debug/leak_annotations.h b/src/base/debug/leak_annotations.h
index 97be127..35a7bec 100644
--- a/src/base/debug/leak_annotations.h
+++ b/src/base/debug/leak_annotations.h
@@ -7,6 +7,17 @@
#include "build/build_config.h"
+// By default, Leak Sanitizer and Address Sanitizer is expected
+// to exist together. However, this is not true for all
+// platforms (e.g. PS4).
+// HAS_LEAK_SANTIZIER=0 explicitly removes the Leak Sanitizer from code.
+#ifdef ADDRESS_SANITIZER
+#ifndef HAS_LEAK_SANITIZER
+// Default is that Leak Sanitizer exists whenever Address Sanitizer does.
+#define HAS_LEAK_SANITIZER 1
+#endif
+#endif
+
#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_NACL) && \
defined(USE_HEAPCHECKER)
@@ -29,7 +40,7 @@
#define ANNOTATE_LEAKING_OBJECT_PTR(X) \
HeapLeakChecker::IgnoreObject(X)
-#elif defined(ADDRESS_SANITIZER)
+#elif defined(ADDRESS_SANITIZER) && HAS_LEAK_SANITIZER
#include <sanitizer/lsan_interface.h>
class ScopedLeakSanitizerDisabler {
diff --git a/src/base/synchronization/condition_variable_unittest.cc b/src/base/synchronization/condition_variable_unittest.cc
index bc8201f..49d138b 100644
--- a/src/base/synchronization/condition_variable_unittest.cc
+++ b/src/base/synchronization/condition_variable_unittest.cc
@@ -350,6 +350,9 @@
// Game consoles don't support that many threads. We have a max threads
// macro in pthread.h. Leave a few to system and test with the rest.
const int kThreadCount = SHELL_MAX_THREADS - 8;
+#elif defined(ADDRESS_SANITIZER)
+ // AddressSanitizer adds additional stack space to the threads.
+ const int kThreadCount = 50;
#elif defined(OS_STARBOARD)
const int kThreadCount = SB_MAX_THREADS - 8;
#else
diff --git a/src/cobalt/account/starboard/account_manager.cc b/src/cobalt/account/starboard/account_manager.cc
index e6b4834..3a546bb 100644
--- a/src/cobalt/account/starboard/account_manager.cc
+++ b/src/cobalt/account/starboard/account_manager.cc
@@ -18,6 +18,7 @@
#include "base/basictypes.h"
#include "base/compiler_specific.h"
+#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "cobalt/base/event_dispatcher.h"
#include "starboard/user.h"
@@ -88,16 +89,13 @@
return GetCurrentUserProperty(kSbUserPropertyUserId);
}
-void AccountManagerStarboard::StartSignIn() { SbUserStartSignIn(); }
+void AccountManagerStarboard::StartSignIn() {
+ NOTREACHED() << "Should be handled internally by platform.";
+}
bool AccountManagerStarboard::IsAgeRestricted() {
- SbUser user = SbUserGetCurrent();
-
- if (!SbUserIsValid(user)) {
- return false;
- }
-
- return SbUserIsAgeRestricted(user);
+ NOTREACHED() << "Should be handled internally by platform.";
+ return false;
}
} // namespace account
diff --git a/src/cobalt/audio/audio_device.cc b/src/cobalt/audio/audio_device.cc
index 9a9e092..5f8d205 100644
--- a/src/cobalt/audio/audio_device.cc
+++ b/src/cobalt/audio/audio_device.cc
@@ -45,6 +45,38 @@
#if defined(SB_USE_SB_AUDIO_SINK)
+namespace {
+// Helper function to compute the size of the two valid starboard audio sample
+// types.
+size_t GetSampleSize(SbMediaAudioSampleType sample_type) {
+ switch (sample_type) {
+ case kSbMediaAudioSampleTypeFloat32:
+ return sizeof(float);
+ case kSbMediaAudioSampleTypeInt16:
+ return sizeof(int16);
+ }
+ NOTREACHED();
+ return 0u;
+}
+
+const float kMaxInt16AsFloat32 = 32767.0f;
+
+template <typename SourceType, typename DestType>
+DestType ConvertSample(SourceType sample);
+
+template <>
+int16 ConvertSample<float, int16>(float sample) {
+ DCHECK(-1.0 <= sample && sample <= 1.0)
+ << "Sample of type float32 must lie on interval [-1.0, 1.0]";
+ return static_cast<int16>(sample * kMaxInt16AsFloat32);
+}
+
+template <>
+float ConvertSample<float, float>(float sample) {
+ return sample;
+}
+} // namespace
+
class AudioDevice::Impl {
public:
Impl(int number_of_channels, RenderCallback* callback);
@@ -62,7 +94,11 @@
void FillOutputAudioBus();
+ template <typename OutputType>
+ inline void FillOutputAudioBusForType();
+
int number_of_channels_;
+ SbMediaAudioSampleType output_sample_type_;
RenderCallback* render_callback_;
// The |render_callback_| returns audio data in planar form. So we read it
@@ -70,11 +106,14 @@
// |output_frame_buffer_|.
ShellAudioBus input_audio_bus_;
- std::vector<float> output_frame_buffer_;
+ scoped_array<uint8> output_frame_buffer_;
+
void* frame_buffers_[1];
int64 frames_rendered_; // Frames retrieved from |render_callback_|.
int64 frames_consumed_; // Accumulated frames consumed reported by the sink.
+ bool was_silence_last_update_;
+
SbAudioSink audio_sink_;
DISALLOW_COPY_AND_ASSIGN(Impl);
@@ -83,13 +122,19 @@
// AudioDevice::Impl.
AudioDevice::Impl::Impl(int number_of_channels, RenderCallback* callback)
: number_of_channels_(number_of_channels),
+ output_sample_type_(
+ SbAudioSinkIsAudioSampleTypeSupported(kSbMediaAudioSampleTypeFloat32)
+ ? kSbMediaAudioSampleTypeFloat32
+ : kSbMediaAudioSampleTypeInt16),
render_callback_(callback),
input_audio_bus_(static_cast<size_t>(number_of_channels),
static_cast<size_t>(kRenderBufferSizeFrames),
ShellAudioBus::kFloat32, ShellAudioBus::kPlanar),
- output_frame_buffer_(kFramesPerChannel * number_of_channels),
+ output_frame_buffer_(new uint8[kFramesPerChannel * number_of_channels_ *
+ GetSampleSize(output_sample_type_)]),
frames_rendered_(0),
frames_consumed_(0),
+ was_silence_last_update_(false),
audio_sink_(kSbAudioSinkInvalid) {
DCHECK(number_of_channels_ == 1 || number_of_channels_ == 2)
<< "Invalid number of channels: " << number_of_channels_;
@@ -97,15 +142,14 @@
DCHECK(SbAudioSinkIsAudioFrameStorageTypeSupported(
kSbMediaAudioFrameStorageTypeInterleaved))
<< "Only interleaved frame storage is supported.";
- DCHECK(SbAudioSinkIsAudioSampleTypeSupported(kSbMediaAudioSampleTypeFloat32))
- << "Only float sample is supported.";
+ DCHECK(SbAudioSinkIsAudioSampleTypeSupported(output_sample_type_))
+ << "Output sample type " << output_sample_type_ << " is not supported";
- frame_buffers_[0] = &output_frame_buffer_[0];
+ frame_buffers_[0] = output_frame_buffer_.get();
audio_sink_ = SbAudioSinkCreate(
- number_of_channels_, kStandardOutputSampleRate,
- kSbMediaAudioSampleTypeFloat32, kSbMediaAudioFrameStorageTypeInterleaved,
- frame_buffers_, kFramesPerChannel,
- &AudioDevice::Impl::UpdateSourceStatusFunc,
+ number_of_channels_, kStandardOutputSampleRate, output_sample_type_,
+ kSbMediaAudioFrameStorageTypeInterleaved, frame_buffers_,
+ kFramesPerChannel, &AudioDevice::Impl::UpdateSourceStatusFunc,
&AudioDevice::Impl::ConsumeFramesFunc, this);
DCHECK(SbAudioSinkIsValid(audio_sink_));
}
@@ -155,7 +199,12 @@
if ((kFramesPerChannel - *frames_in_buffer) >= kRenderBufferSizeFrames) {
bool silence = false;
- input_audio_bus_.ZeroAllFrames();
+ // If there was silence last time we were called, then the buffer has
+ // already been zeroed out and we don't need to do it again.
+ if (!was_silence_last_update_) {
+ input_audio_bus_.ZeroAllFrames();
+ }
+
// Fill our temporary buffer with planar PCM float samples.
render_callback_->FillAudioBus(&input_audio_bus_, &silence);
@@ -165,31 +214,46 @@
frames_rendered_ += kRenderBufferSizeFrames;
*frames_in_buffer += kRenderBufferSizeFrames;
}
+
+ was_silence_last_update_ = silence;
}
*offset_in_frames = frames_consumed_ % kFramesPerChannel;
+ *is_playing = (frames_rendered_ != frames_consumed_);
}
void AudioDevice::Impl::ConsumeFrames(int frames_consumed) {
frames_consumed_ += frames_consumed;
}
-void AudioDevice::Impl::FillOutputAudioBus() {
+template <typename OutputType>
+inline void AudioDevice::Impl::FillOutputAudioBusForType() {
// Determine the offset into the audio bus that represents the tail of
// buffered data.
uint64 channel_offset = frames_rendered_ % kFramesPerChannel;
- float* output_buffer = &output_frame_buffer_[0];
+ OutputType* output_buffer =
+ reinterpret_cast<OutputType*>(output_frame_buffer_.get());
output_buffer += channel_offset * number_of_channels_;
-
for (size_t frame = 0; frame < kRenderBufferSizeFrames; ++frame) {
for (size_t channel = 0; channel < input_audio_bus_.channels(); ++channel) {
- *output_buffer = input_audio_bus_.GetFloat32Sample(channel, frame);
+ *output_buffer = ConvertSample<float, OutputType>(
+ input_audio_bus_.GetFloat32Sample(channel, frame));
++output_buffer;
}
}
}
+void AudioDevice::Impl::FillOutputAudioBus() {
+ if (output_sample_type_ == kSbMediaAudioSampleTypeFloat32) {
+ FillOutputAudioBusForType<float>();
+ } else if (output_sample_type_ == kSbMediaAudioSampleTypeInt16) {
+ FillOutputAudioBusForType<int16>();
+ } else {
+ NOTREACHED();
+ }
+}
+
#else // defined(SB_USE_SB_AUDIO_SINK)
class AudioDevice::Impl : public ::media::ShellAudioStream {
diff --git a/src/cobalt/base/c_val.cc b/src/cobalt/base/c_val.cc
index e719bb5..812433b 100644
--- a/src/cobalt/base/c_val.cc
+++ b/src/cobalt/base/c_val.cc
@@ -29,15 +29,15 @@
// and so this allows its size to be more consistent (and avoids compiler
// warnings on some platforms).
registered_vars_ = new NameVarMap();
-#if defined(ENABLE_DEBUG_CONSOLE)
+#if defined(ENABLE_DEBUG_C_VAL)
on_changed_hook_set_ = new base::hash_set<OnChangedHook*>();
-#endif // ENABLE_DEBUG_CONSOLE
+#endif // ENABLE_DEBUG_C_VAL
}
CValManager::~CValManager() {
-#if defined(ENABLE_DEBUG_CONSOLE)
+#if defined(ENABLE_DEBUG_C_VAL)
delete on_changed_hook_set_;
-#endif // ENABLE_DEBUG_CONSOLE
+#endif // ENABLE_DEBUG_C_VAL
delete registered_vars_;
}
@@ -62,7 +62,7 @@
}
}
-#if defined(ENABLE_DEBUG_CONSOLE)
+#if defined(ENABLE_DEBUG_C_VAL)
void CValManager::PushValueChangedEvent(const CValDetail::CValBase* cval,
const CValGenericValue& value) {
base::AutoLock auto_lock(hooks_lock_);
@@ -92,7 +92,7 @@
size_t values_erased ALLOW_UNUSED = cvm->on_changed_hook_set_->erase(this);
DCHECK_EQ(values_erased, 1);
}
-#endif // ENABLE_DEBUG_CONSOLE
+#endif // ENABLE_DEBUG_C_VAL
std::set<std::string> CValManager::GetOrderedCValNames() {
std::set<std::string> ret;
diff --git a/src/cobalt/base/c_val.h b/src/cobalt/base/c_val.h
index 767fdb6..787f51a 100644
--- a/src/cobalt/base/c_val.h
+++ b/src/cobalt/base/c_val.h
@@ -217,7 +217,7 @@
} // namespace CValDetail
-#if defined(ENABLE_DEBUG_CONSOLE)
+#if defined(ENABLE_DEBUG_C_VAL)
// This class is passed back to the CVal modified event handlers so that they
// can examine the new CVal value. This class knows its type, which can be
// checked through GetType, and then the actual value can be retrieved by
@@ -281,7 +281,7 @@
};
} // namespace CValDetail
-#endif // ENABLE_DEBUG_CONSOLE
+#endif // ENABLE_DEBUG_C_VAL
// Manager class required for the CVal tracking system to function.
// This class is designed to be a singleton, instanced only through the methods
@@ -292,7 +292,7 @@
// Method to get the singleton instance of this class.
static CValManager* GetInstance();
-#if defined(ENABLE_DEBUG_CONSOLE)
+#if defined(ENABLE_DEBUG_C_VAL)
// In order for a system to receive notifications when a tracked CVal changes,
// it should create a subclass of OnChangedHook with OnValueChanged. When
// instantiated, OnChangedHook will be called whenever a CVal changes.
@@ -304,7 +304,7 @@
virtual void OnValueChanged(const std::string& name,
const CValGenericValue& value) = 0;
};
-#endif // ENABLE_DEBUG_CONSOLE
+#endif // ENABLE_DEBUG_C_VAL
friend struct StaticMemorySingletonTraits<CValManager>;
@@ -332,22 +332,22 @@
void RegisterCVal(const CValDetail::CValBase* cval);
void UnregisterCVal(const CValDetail::CValBase* cval);
-#if defined(ENABLE_DEBUG_CONSOLE)
+#if defined(ENABLE_DEBUG_C_VAL)
// Called whenever a CVal is modified, and does the work of notifying all
// hooks.
void PushValueChangedEvent(const CValDetail::CValBase* cval,
const CValGenericValue& value);
-#endif // ENABLE_DEBUG_CONSOLE
+#endif // ENABLE_DEBUG_C_VAL
// Helper function to remove code duplication between GetValueAsString
// and GetValueAsPrettyString.
optional<std::string> GetCValStringValue(const std::string& name,
bool pretty);
-#if defined(ENABLE_DEBUG_CONSOLE)
+#if defined(ENABLE_DEBUG_C_VAL)
// Lock that protects against changes to hooks.
base::Lock hooks_lock_;
-#endif // ENABLE_DEBUG_CONSOLE
+#endif // ENABLE_DEBUG_C_VAL
// Lock that protects against CVals being registered/deregistered.
base::Lock cvals_lock_;
@@ -359,11 +359,11 @@
typedef base::hash_map<std::string, const CValDetail::CValBase*> NameVarMap;
NameVarMap* registered_vars_;
-#if defined(ENABLE_DEBUG_CONSOLE)
+#if defined(ENABLE_DEBUG_C_VAL)
// The set of hooks that we should notify whenever a CVal is modified.
typedef base::hash_set<OnChangedHook*> OnChangeHookSet;
OnChangeHookSet* on_changed_hook_set_;
-#endif // ENABLE_DEBUG_CONSOLE
+#endif // ENABLE_DEBUG_C_VAL
template <typename T>
friend class CValDetail::CValImpl;
@@ -427,11 +427,11 @@
value_ = rhs;
}
}
-#if defined(ENABLE_DEBUG_CONSOLE)
+#if defined(ENABLE_DEBUG_C_VAL)
if (value_changed) {
OnValueChanged();
}
-#endif // ENABLE_DEBUG_CONSOLE
+#endif // ENABLE_DEBUG_C_VAL
return *this;
}
@@ -440,9 +440,9 @@
base::AutoLock auto_lock(CValManager::GetInstance()->values_lock_);
value_ += rhs;
}
-#if defined(ENABLE_DEBUG_CONSOLE)
+#if defined(ENABLE_DEBUG_C_VAL)
OnValueChanged();
-#endif // ENABLE_DEBUG_CONSOLE
+#endif // ENABLE_DEBUG_C_VAL
return *this;
}
@@ -451,9 +451,9 @@
base::AutoLock auto_lock(CValManager::GetInstance()->values_lock_);
value_ -= rhs;
}
-#if defined(ENABLE_DEBUG_CONSOLE)
+#if defined(ENABLE_DEBUG_C_VAL)
OnValueChanged();
-#endif // ENABLE_DEBUG_CONSOLE
+#endif // ENABLE_DEBUG_C_VAL
return *this;
}
@@ -462,9 +462,9 @@
base::AutoLock auto_lock(CValManager::GetInstance()->values_lock_);
++value_;
}
-#if defined(ENABLE_DEBUG_CONSOLE)
+#if defined(ENABLE_DEBUG_C_VAL)
OnValueChanged();
-#endif // ENABLE_DEBUG_CONSOLE
+#endif // ENABLE_DEBUG_C_VAL
return *this;
}
@@ -473,9 +473,9 @@
base::AutoLock auto_lock(CValManager::GetInstance()->values_lock_);
--value_;
}
-#if defined(ENABLE_DEBUG_CONSOLE)
+#if defined(ENABLE_DEBUG_C_VAL)
OnValueChanged();
-#endif // ENABLE_DEBUG_CONSOLE
+#endif // ENABLE_DEBUG_C_VAL
return *this;
}
@@ -505,13 +505,13 @@
}
}
-#if defined(ENABLE_DEBUG_CONSOLE)
+#if defined(ENABLE_DEBUG_C_VAL)
void OnValueChanged() {
// Push the value changed event to all listeners.
CValManager::GetInstance()->PushValueChangedEvent(
this, CValSpecificValue<T>(value_));
}
-#endif // ENABLE_DEBUG_CONSOLE
+#endif // ENABLE_DEBUG_C_VAL
T value_;
mutable bool registered_;
diff --git a/src/cobalt/bindings/IDLExtendedAttributes.txt b/src/cobalt/bindings/IDLExtendedAttributes.txt
index 56b0590..7918baa 100644
--- a/src/cobalt/bindings/IDLExtendedAttributes.txt
+++ b/src/cobalt/bindings/IDLExtendedAttributes.txt
@@ -73,7 +73,9 @@
# Call the Cobalt function this property is bound to with the corresponding
# object added to the head of the function's parameters.
-CallWith=EnvironmentSettings
+# StackTrace is a custom addition to CallWith for the purpose of testing
+# GetStackTrace, and is not specified in the spec.
+CallWith=EnvironmentSettings|StackTrace
ConstructorCallWith=EnvironmentSettings
# The constructor/attribute/operation may raise an exception. A pointer to an
diff --git a/src/cobalt/bindings/generated/jsc/testing/JSCWindow.cc b/src/cobalt/bindings/generated/jsc/testing/JSCWindow.cc
index 32f9f26..1fb9cf2 100644
--- a/src/cobalt/bindings/generated/jsc/testing/JSCWindow.cc
+++ b/src/cobalt/bindings/generated/jsc/testing/JSCWindow.cc
@@ -287,6 +287,11 @@
JSC::ExecState* exec,
JSC::JSObject* this_object,
JSC::JSValue value);
+JSC::JSValue getJSwindow(
+ JSC::ExecState* exec_state,
+ JSC::JSValue slot_base,
+ JSC::PropertyName property_name);
+JSC::EncodedJSValue functionJSgetStackTrace(JSC::ExecState*);
JSC::EncodedJSValue functionJSwindowOperation(JSC::ExecState*);
// These are declared unconditionally, but only defined if needed by the
@@ -603,6 +608,18 @@
reinterpret_cast<intptr_t>(setJSwindowProperty),
JSC::NoIntrinsic
},
+ { "window",
+ JSC::DontDelete | JSC::ReadOnly,
+ reinterpret_cast<intptr_t>(getJSwindow),
+ 0,
+ JSC::NoIntrinsic
+ },
+ { "getStackTrace",
+ JSC::DontDelete | JSC::Function,
+ reinterpret_cast<intptr_t>(functionJSgetStackTrace),
+ static_cast<intptr_t>(0),
+ JSC::NoIntrinsic
+ },
{ "windowOperation",
JSC::DontDelete | JSC::Function,
reinterpret_cast<intptr_t>(functionJSwindowOperation),
@@ -614,8 +631,8 @@
// static
const JSC::HashTable JSCWindow::property_table_prototype = {
- 9, // compactSize
- 7, // compactSizeMask
+ 19, // compactSize
+ 15, // compactSizeMask
property_table_values,
NULL // table allocated at runtime
}; // JSCWindow::property_table_prototype
@@ -1019,6 +1036,44 @@
}
}
+JSC::JSValue getJSwindow(
+ JSC::ExecState* exec_state,
+ JSC::JSValue slot_base,
+ JSC::PropertyName property_name) {
+ TRACE_EVENT0("JSCWindow", "get window");
+ JSCGlobalObject* global_object =
+ JSC::jsCast<JSCGlobalObject*>(exec_state->lexicalGlobalObject());
+ Window* impl =
+ GetWrappableOrSetException<Window>(exec_state, slot_base);
+ if (!impl) {
+ return exec_state->exception();
+ }
+
+ JSC::JSValue result = ToJSValue(
+ global_object,
+ impl->window());
+ return result;
+}
+
+JSC::EncodedJSValue functionJSgetStackTrace(
+ JSC::ExecState* exec_state) {
+ TRACE_EVENT0("JSCWindow", "call getStackTrace");
+ JSCGlobalObject* global_object =
+ JSC::jsCast<JSCGlobalObject*>(exec_state->lexicalGlobalObject());
+ JSCExceptionState exception_state(global_object);
+ JSC::JSObject* this_object =
+ exec_state->hostThisValue().toThisObject(exec_state);
+ Window* impl =
+ GetWrappableOrSetException<Window>(exec_state, this_object);
+ if (!impl) {
+ return JSC::JSValue::encode(exec_state->exception());
+ }
+
+ TypeTraits<std::string >::ReturnType return_value = impl->GetStackTrace(global_object->GetStackTrace());
+ return JSC::JSValue::encode(ToJSValue(global_object, return_value));
+
+}
+
JSC::EncodedJSValue functionJSwindowOperation(
JSC::ExecState* exec_state) {
TRACE_EVENT0("JSCWindow", "call windowOperation");
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsAnonymousIndexedGetterInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsAnonymousIndexedGetterInterface.cc
index d314658..546197c 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsAnonymousIndexedGetterInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsAnonymousIndexedGetterInterface.cc
@@ -205,6 +205,26 @@
static base::LazyInstance<MozjsAnonymousIndexedGetterInterfaceHandler>
proxy_handler;
+JSBool HasInstance(JSContext *context, JS::HandleObject type,
+ JS::MutableHandleValue vp, JSBool *success) {
+ JS::RootedObject global_object(
+ context, JS_GetGlobalForObject(context, type));
+ DCHECK(global_object);
+
+ JS::RootedObject prototype(
+ context, MozjsAnonymousIndexedGetterInterface::GetPrototype(context, global_object));
+
+ // |IsDelegate| walks the prototype chain of an object returning true if
+ // .prototype is found.
+ bool is_delegate;
+ if (!IsDelegate(context, prototype, vp, &is_delegate)) {
+ *success = false;
+ return false;
+ }
+
+ *success = is_delegate;
+ return true;
+}
InterfaceData* CreateCachedInterfaceData() {
InterfaceData* interface_data = new InterfaceData();
@@ -253,6 +273,7 @@
interface_object_class->enumerate = JS_EnumerateStub;
interface_object_class->resolve = JS_ResolveStub;
interface_object_class->convert = JS_ConvertStub;
+ interface_object_class->hasInstance = &HasInstance;
return interface_data;
}
@@ -306,14 +327,12 @@
};
void InitializePrototypeAndInterfaceObject(
- InterfaceData* interface_data, JSContext* context) {
+ InterfaceData* interface_data, JSContext* context,
+ JS::HandleObject global_object) {
DCHECK(!interface_data->prototype);
DCHECK(!interface_data->interface_object);
+ DCHECK(JS_IsGlobalObject(global_object));
- MozjsGlobalObjectProxy* global_object_proxy =
- static_cast<MozjsGlobalObjectProxy*>(JS_GetContextPrivate(context));
- JS::RootedObject global_object(context, global_object_proxy->global_object());
- DCHECK(global_object);
JS::RootedObject parent_prototype(
context, JS_GetObjectPrototype(context, global_object));
DCHECK(parent_prototype);
@@ -392,8 +411,11 @@
// static
JSObject* MozjsAnonymousIndexedGetterInterface::CreateProxy(
JSContext* context, const scoped_refptr<Wrappable>& wrappable) {
+ JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+ DCHECK(global_object);
+
InterfaceData* interface_data = GetInterfaceData(context);
- JS::RootedObject prototype(context, GetPrototype(context));
+ JS::RootedObject prototype(context, GetPrototype(context, global_object));
DCHECK(prototype);
JS::RootedObject new_object(context, JS_NewObjectWithGivenProto(
context, &interface_data->instance_class_definition, prototype, NULL));
@@ -401,34 +423,45 @@
JS::RootedObject proxy(context,
ProxyHandler::NewProxy(context, new_object, prototype, NULL,
proxy_handler.Pointer()));
- WrapperPrivate::AddPrivateData(proxy, wrappable);
+ WrapperPrivate::AddPrivateData(context, proxy, wrappable);
return proxy;
}
//static
const JSClass* MozjsAnonymousIndexedGetterInterface::PrototypeClass(
JSContext* context) {
- JS::RootedObject prototype(context, GetPrototype(context));
+ JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+ DCHECK(global_object);
+
+ JS::RootedObject prototype(context, GetPrototype(context, global_object));
JSClass* proto_class = JS_GetClass(*prototype.address());
return proto_class;
}
// static
-JSObject* MozjsAnonymousIndexedGetterInterface::GetPrototype(JSContext* context) {
+JSObject* MozjsAnonymousIndexedGetterInterface::GetPrototype(
+ JSContext* context, JS::HandleObject global_object) {
+ DCHECK(JS_IsGlobalObject(global_object));
+
InterfaceData* interface_data = GetInterfaceData(context);
if (!interface_data->prototype) {
// Create new prototype that has all the props and methods
- InitializePrototypeAndInterfaceObject(interface_data, context);
+ InitializePrototypeAndInterfaceObject(
+ interface_data, context, global_object);
}
DCHECK(interface_data->prototype);
return interface_data->prototype;
}
// static
-JSObject* MozjsAnonymousIndexedGetterInterface::GetInterfaceObject(JSContext* context) {
+JSObject* MozjsAnonymousIndexedGetterInterface::GetInterfaceObject(
+ JSContext* context, JS::HandleObject global_object) {
+ DCHECK(JS_IsGlobalObject(global_object));
+
InterfaceData* interface_data = GetInterfaceData(context);
if (!interface_data->interface_object) {
- InitializePrototypeAndInterfaceObject(interface_data, context);
+ InitializePrototypeAndInterfaceObject(
+ interface_data, context, global_object);
}
DCHECK(interface_data->interface_object);
return interface_data->interface_object;
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsAnonymousIndexedGetterInterface.h b/src/cobalt/bindings/generated/mozjs/testing/MozjsAnonymousIndexedGetterInterface.h
index 56a2226..1f01c81 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsAnonymousIndexedGetterInterface.h
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsAnonymousIndexedGetterInterface.h
@@ -41,8 +41,10 @@
static JSObject* CreateProxy(JSContext* context,
const scoped_refptr<script::Wrappable>& wrappable);
static const JSClass* PrototypeClass(JSContext* context);
- static JSObject* GetPrototype(JSContext* context);
- static JSObject* GetInterfaceObject(JSContext* context);
+ static JSObject* GetPrototype(JSContext* context,
+ JS::HandleObject global_object);
+ static JSObject* GetInterfaceObject(JSContext* context,
+ JS::HandleObject global_object);
};
} // namespace bindings
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsAnonymousNamedGetterInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsAnonymousNamedGetterInterface.cc
index 7cc34a6..9cb9a00 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsAnonymousNamedGetterInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsAnonymousNamedGetterInterface.cc
@@ -205,6 +205,26 @@
static base::LazyInstance<MozjsAnonymousNamedGetterInterfaceHandler>
proxy_handler;
+JSBool HasInstance(JSContext *context, JS::HandleObject type,
+ JS::MutableHandleValue vp, JSBool *success) {
+ JS::RootedObject global_object(
+ context, JS_GetGlobalForObject(context, type));
+ DCHECK(global_object);
+
+ JS::RootedObject prototype(
+ context, MozjsAnonymousNamedGetterInterface::GetPrototype(context, global_object));
+
+ // |IsDelegate| walks the prototype chain of an object returning true if
+ // .prototype is found.
+ bool is_delegate;
+ if (!IsDelegate(context, prototype, vp, &is_delegate)) {
+ *success = false;
+ return false;
+ }
+
+ *success = is_delegate;
+ return true;
+}
InterfaceData* CreateCachedInterfaceData() {
InterfaceData* interface_data = new InterfaceData();
@@ -253,6 +273,7 @@
interface_object_class->enumerate = JS_EnumerateStub;
interface_object_class->resolve = JS_ResolveStub;
interface_object_class->convert = JS_ConvertStub;
+ interface_object_class->hasInstance = &HasInstance;
return interface_data;
}
@@ -278,14 +299,12 @@
};
void InitializePrototypeAndInterfaceObject(
- InterfaceData* interface_data, JSContext* context) {
+ InterfaceData* interface_data, JSContext* context,
+ JS::HandleObject global_object) {
DCHECK(!interface_data->prototype);
DCHECK(!interface_data->interface_object);
+ DCHECK(JS_IsGlobalObject(global_object));
- MozjsGlobalObjectProxy* global_object_proxy =
- static_cast<MozjsGlobalObjectProxy*>(JS_GetContextPrivate(context));
- JS::RootedObject global_object(context, global_object_proxy->global_object());
- DCHECK(global_object);
JS::RootedObject parent_prototype(
context, JS_GetObjectPrototype(context, global_object));
DCHECK(parent_prototype);
@@ -364,8 +383,11 @@
// static
JSObject* MozjsAnonymousNamedGetterInterface::CreateProxy(
JSContext* context, const scoped_refptr<Wrappable>& wrappable) {
+ JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+ DCHECK(global_object);
+
InterfaceData* interface_data = GetInterfaceData(context);
- JS::RootedObject prototype(context, GetPrototype(context));
+ JS::RootedObject prototype(context, GetPrototype(context, global_object));
DCHECK(prototype);
JS::RootedObject new_object(context, JS_NewObjectWithGivenProto(
context, &interface_data->instance_class_definition, prototype, NULL));
@@ -373,34 +395,45 @@
JS::RootedObject proxy(context,
ProxyHandler::NewProxy(context, new_object, prototype, NULL,
proxy_handler.Pointer()));
- WrapperPrivate::AddPrivateData(proxy, wrappable);
+ WrapperPrivate::AddPrivateData(context, proxy, wrappable);
return proxy;
}
//static
const JSClass* MozjsAnonymousNamedGetterInterface::PrototypeClass(
JSContext* context) {
- JS::RootedObject prototype(context, GetPrototype(context));
+ JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+ DCHECK(global_object);
+
+ JS::RootedObject prototype(context, GetPrototype(context, global_object));
JSClass* proto_class = JS_GetClass(*prototype.address());
return proto_class;
}
// static
-JSObject* MozjsAnonymousNamedGetterInterface::GetPrototype(JSContext* context) {
+JSObject* MozjsAnonymousNamedGetterInterface::GetPrototype(
+ JSContext* context, JS::HandleObject global_object) {
+ DCHECK(JS_IsGlobalObject(global_object));
+
InterfaceData* interface_data = GetInterfaceData(context);
if (!interface_data->prototype) {
// Create new prototype that has all the props and methods
- InitializePrototypeAndInterfaceObject(interface_data, context);
+ InitializePrototypeAndInterfaceObject(
+ interface_data, context, global_object);
}
DCHECK(interface_data->prototype);
return interface_data->prototype;
}
// static
-JSObject* MozjsAnonymousNamedGetterInterface::GetInterfaceObject(JSContext* context) {
+JSObject* MozjsAnonymousNamedGetterInterface::GetInterfaceObject(
+ JSContext* context, JS::HandleObject global_object) {
+ DCHECK(JS_IsGlobalObject(global_object));
+
InterfaceData* interface_data = GetInterfaceData(context);
if (!interface_data->interface_object) {
- InitializePrototypeAndInterfaceObject(interface_data, context);
+ InitializePrototypeAndInterfaceObject(
+ interface_data, context, global_object);
}
DCHECK(interface_data->interface_object);
return interface_data->interface_object;
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsAnonymousNamedGetterInterface.h b/src/cobalt/bindings/generated/mozjs/testing/MozjsAnonymousNamedGetterInterface.h
index 36537ae..3b02269 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsAnonymousNamedGetterInterface.h
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsAnonymousNamedGetterInterface.h
@@ -41,8 +41,10 @@
static JSObject* CreateProxy(JSContext* context,
const scoped_refptr<script::Wrappable>& wrappable);
static const JSClass* PrototypeClass(JSContext* context);
- static JSObject* GetPrototype(JSContext* context);
- static JSObject* GetInterfaceObject(JSContext* context);
+ static JSObject* GetPrototype(JSContext* context,
+ JS::HandleObject global_object);
+ static JSObject* GetInterfaceObject(JSContext* context,
+ JS::HandleObject global_object);
};
} // namespace bindings
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsAnonymousNamedIndexedGetterInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsAnonymousNamedIndexedGetterInterface.cc
index 519c86f..0b1e79d 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsAnonymousNamedIndexedGetterInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsAnonymousNamedIndexedGetterInterface.cc
@@ -296,6 +296,26 @@
static base::LazyInstance<MozjsAnonymousNamedIndexedGetterInterfaceHandler>
proxy_handler;
+JSBool HasInstance(JSContext *context, JS::HandleObject type,
+ JS::MutableHandleValue vp, JSBool *success) {
+ JS::RootedObject global_object(
+ context, JS_GetGlobalForObject(context, type));
+ DCHECK(global_object);
+
+ JS::RootedObject prototype(
+ context, MozjsAnonymousNamedIndexedGetterInterface::GetPrototype(context, global_object));
+
+ // |IsDelegate| walks the prototype chain of an object returning true if
+ // .prototype is found.
+ bool is_delegate;
+ if (!IsDelegate(context, prototype, vp, &is_delegate)) {
+ *success = false;
+ return false;
+ }
+
+ *success = is_delegate;
+ return true;
+}
InterfaceData* CreateCachedInterfaceData() {
InterfaceData* interface_data = new InterfaceData();
@@ -344,6 +364,7 @@
interface_object_class->enumerate = JS_EnumerateStub;
interface_object_class->resolve = JS_ResolveStub;
interface_object_class->convert = JS_ConvertStub;
+ interface_object_class->hasInstance = &HasInstance;
return interface_data;
}
@@ -397,14 +418,12 @@
};
void InitializePrototypeAndInterfaceObject(
- InterfaceData* interface_data, JSContext* context) {
+ InterfaceData* interface_data, JSContext* context,
+ JS::HandleObject global_object) {
DCHECK(!interface_data->prototype);
DCHECK(!interface_data->interface_object);
+ DCHECK(JS_IsGlobalObject(global_object));
- MozjsGlobalObjectProxy* global_object_proxy =
- static_cast<MozjsGlobalObjectProxy*>(JS_GetContextPrivate(context));
- JS::RootedObject global_object(context, global_object_proxy->global_object());
- DCHECK(global_object);
JS::RootedObject parent_prototype(
context, JS_GetObjectPrototype(context, global_object));
DCHECK(parent_prototype);
@@ -483,8 +502,11 @@
// static
JSObject* MozjsAnonymousNamedIndexedGetterInterface::CreateProxy(
JSContext* context, const scoped_refptr<Wrappable>& wrappable) {
+ JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+ DCHECK(global_object);
+
InterfaceData* interface_data = GetInterfaceData(context);
- JS::RootedObject prototype(context, GetPrototype(context));
+ JS::RootedObject prototype(context, GetPrototype(context, global_object));
DCHECK(prototype);
JS::RootedObject new_object(context, JS_NewObjectWithGivenProto(
context, &interface_data->instance_class_definition, prototype, NULL));
@@ -492,34 +514,45 @@
JS::RootedObject proxy(context,
ProxyHandler::NewProxy(context, new_object, prototype, NULL,
proxy_handler.Pointer()));
- WrapperPrivate::AddPrivateData(proxy, wrappable);
+ WrapperPrivate::AddPrivateData(context, proxy, wrappable);
return proxy;
}
//static
const JSClass* MozjsAnonymousNamedIndexedGetterInterface::PrototypeClass(
JSContext* context) {
- JS::RootedObject prototype(context, GetPrototype(context));
+ JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+ DCHECK(global_object);
+
+ JS::RootedObject prototype(context, GetPrototype(context, global_object));
JSClass* proto_class = JS_GetClass(*prototype.address());
return proto_class;
}
// static
-JSObject* MozjsAnonymousNamedIndexedGetterInterface::GetPrototype(JSContext* context) {
+JSObject* MozjsAnonymousNamedIndexedGetterInterface::GetPrototype(
+ JSContext* context, JS::HandleObject global_object) {
+ DCHECK(JS_IsGlobalObject(global_object));
+
InterfaceData* interface_data = GetInterfaceData(context);
if (!interface_data->prototype) {
// Create new prototype that has all the props and methods
- InitializePrototypeAndInterfaceObject(interface_data, context);
+ InitializePrototypeAndInterfaceObject(
+ interface_data, context, global_object);
}
DCHECK(interface_data->prototype);
return interface_data->prototype;
}
// static
-JSObject* MozjsAnonymousNamedIndexedGetterInterface::GetInterfaceObject(JSContext* context) {
+JSObject* MozjsAnonymousNamedIndexedGetterInterface::GetInterfaceObject(
+ JSContext* context, JS::HandleObject global_object) {
+ DCHECK(JS_IsGlobalObject(global_object));
+
InterfaceData* interface_data = GetInterfaceData(context);
if (!interface_data->interface_object) {
- InitializePrototypeAndInterfaceObject(interface_data, context);
+ InitializePrototypeAndInterfaceObject(
+ interface_data, context, global_object);
}
DCHECK(interface_data->interface_object);
return interface_data->interface_object;
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsAnonymousNamedIndexedGetterInterface.h b/src/cobalt/bindings/generated/mozjs/testing/MozjsAnonymousNamedIndexedGetterInterface.h
index 6665fe1..3c53111 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsAnonymousNamedIndexedGetterInterface.h
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsAnonymousNamedIndexedGetterInterface.h
@@ -41,8 +41,10 @@
static JSObject* CreateProxy(JSContext* context,
const scoped_refptr<script::Wrappable>& wrappable);
static const JSClass* PrototypeClass(JSContext* context);
- static JSObject* GetPrototype(JSContext* context);
- static JSObject* GetInterfaceObject(JSContext* context);
+ static JSObject* GetPrototype(JSContext* context,
+ JS::HandleObject global_object);
+ static JSObject* GetInterfaceObject(JSContext* context,
+ JS::HandleObject global_object);
};
} // namespace bindings
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsArbitraryInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsArbitraryInterface.cc
index eb16ae9..4073689 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsArbitraryInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsArbitraryInterface.cc
@@ -115,6 +115,26 @@
proxy_handler;
JSBool Constructor(JSContext* context, unsigned int argc, JS::Value* vp);
+JSBool HasInstance(JSContext *context, JS::HandleObject type,
+ JS::MutableHandleValue vp, JSBool *success) {
+ JS::RootedObject global_object(
+ context, JS_GetGlobalForObject(context, type));
+ DCHECK(global_object);
+
+ JS::RootedObject prototype(
+ context, MozjsArbitraryInterface::GetPrototype(context, global_object));
+
+ // |IsDelegate| walks the prototype chain of an object returning true if
+ // .prototype is found.
+ bool is_delegate;
+ if (!IsDelegate(context, prototype, vp, &is_delegate)) {
+ *success = false;
+ return false;
+ }
+
+ *success = is_delegate;
+ return true;
+}
InterfaceData* CreateCachedInterfaceData() {
InterfaceData* interface_data = new InterfaceData();
@@ -163,6 +183,7 @@
interface_object_class->enumerate = JS_EnumerateStub;
interface_object_class->resolve = JS_ResolveStub;
interface_object_class->convert = JS_ConvertStub;
+ interface_object_class->hasInstance = &HasInstance;
interface_object_class->construct = Constructor;
return interface_data;
}
@@ -274,14 +295,12 @@
};
void InitializePrototypeAndInterfaceObject(
- InterfaceData* interface_data, JSContext* context) {
+ InterfaceData* interface_data, JSContext* context,
+ JS::HandleObject global_object) {
DCHECK(!interface_data->prototype);
DCHECK(!interface_data->interface_object);
+ DCHECK(JS_IsGlobalObject(global_object));
- MozjsGlobalObjectProxy* global_object_proxy =
- static_cast<MozjsGlobalObjectProxy*>(JS_GetContextPrivate(context));
- JS::RootedObject global_object(context, global_object_proxy->global_object());
- DCHECK(global_object);
JS::RootedObject parent_prototype(
context, JS_GetObjectPrototype(context, global_object));
DCHECK(parent_prototype);
@@ -370,8 +389,11 @@
// static
JSObject* MozjsArbitraryInterface::CreateProxy(
JSContext* context, const scoped_refptr<Wrappable>& wrappable) {
+ JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+ DCHECK(global_object);
+
InterfaceData* interface_data = GetInterfaceData(context);
- JS::RootedObject prototype(context, GetPrototype(context));
+ JS::RootedObject prototype(context, GetPrototype(context, global_object));
DCHECK(prototype);
JS::RootedObject new_object(context, JS_NewObjectWithGivenProto(
context, &interface_data->instance_class_definition, prototype, NULL));
@@ -379,34 +401,45 @@
JS::RootedObject proxy(context,
ProxyHandler::NewProxy(context, new_object, prototype, NULL,
proxy_handler.Pointer()));
- WrapperPrivate::AddPrivateData(proxy, wrappable);
+ WrapperPrivate::AddPrivateData(context, proxy, wrappable);
return proxy;
}
//static
const JSClass* MozjsArbitraryInterface::PrototypeClass(
JSContext* context) {
- JS::RootedObject prototype(context, GetPrototype(context));
+ JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+ DCHECK(global_object);
+
+ JS::RootedObject prototype(context, GetPrototype(context, global_object));
JSClass* proto_class = JS_GetClass(*prototype.address());
return proto_class;
}
// static
-JSObject* MozjsArbitraryInterface::GetPrototype(JSContext* context) {
+JSObject* MozjsArbitraryInterface::GetPrototype(
+ JSContext* context, JS::HandleObject global_object) {
+ DCHECK(JS_IsGlobalObject(global_object));
+
InterfaceData* interface_data = GetInterfaceData(context);
if (!interface_data->prototype) {
// Create new prototype that has all the props and methods
- InitializePrototypeAndInterfaceObject(interface_data, context);
+ InitializePrototypeAndInterfaceObject(
+ interface_data, context, global_object);
}
DCHECK(interface_data->prototype);
return interface_data->prototype;
}
// static
-JSObject* MozjsArbitraryInterface::GetInterfaceObject(JSContext* context) {
+JSObject* MozjsArbitraryInterface::GetInterfaceObject(
+ JSContext* context, JS::HandleObject global_object) {
+ DCHECK(JS_IsGlobalObject(global_object));
+
InterfaceData* interface_data = GetInterfaceData(context);
if (!interface_data->interface_object) {
- InitializePrototypeAndInterfaceObject(interface_data, context);
+ InitializePrototypeAndInterfaceObject(
+ interface_data, context, global_object);
}
DCHECK(interface_data->interface_object);
return interface_data->interface_object;
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsArbitraryInterface.h b/src/cobalt/bindings/generated/mozjs/testing/MozjsArbitraryInterface.h
index 1ca5d0d..d1f6fa5 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsArbitraryInterface.h
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsArbitraryInterface.h
@@ -41,8 +41,10 @@
static JSObject* CreateProxy(JSContext* context,
const scoped_refptr<script::Wrappable>& wrappable);
static const JSClass* PrototypeClass(JSContext* context);
- static JSObject* GetPrototype(JSContext* context);
- static JSObject* GetInterfaceObject(JSContext* context);
+ static JSObject* GetPrototype(JSContext* context,
+ JS::HandleObject global_object);
+ static JSObject* GetInterfaceObject(JSContext* context,
+ JS::HandleObject global_object);
};
} // namespace bindings
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsBaseInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsBaseInterface.cc
index 1213bf6..f0e5922 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsBaseInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsBaseInterface.cc
@@ -115,6 +115,26 @@
proxy_handler;
JSBool Constructor(JSContext* context, unsigned int argc, JS::Value* vp);
+JSBool HasInstance(JSContext *context, JS::HandleObject type,
+ JS::MutableHandleValue vp, JSBool *success) {
+ JS::RootedObject global_object(
+ context, JS_GetGlobalForObject(context, type));
+ DCHECK(global_object);
+
+ JS::RootedObject prototype(
+ context, MozjsBaseInterface::GetPrototype(context, global_object));
+
+ // |IsDelegate| walks the prototype chain of an object returning true if
+ // .prototype is found.
+ bool is_delegate;
+ if (!IsDelegate(context, prototype, vp, &is_delegate)) {
+ *success = false;
+ return false;
+ }
+
+ *success = is_delegate;
+ return true;
+}
InterfaceData* CreateCachedInterfaceData() {
InterfaceData* interface_data = new InterfaceData();
@@ -163,6 +183,7 @@
interface_object_class->enumerate = JS_EnumerateStub;
interface_object_class->resolve = JS_ResolveStub;
interface_object_class->convert = JS_ConvertStub;
+ interface_object_class->hasInstance = &HasInstance;
interface_object_class->construct = Constructor;
return interface_data;
}
@@ -252,14 +273,12 @@
};
void InitializePrototypeAndInterfaceObject(
- InterfaceData* interface_data, JSContext* context) {
+ InterfaceData* interface_data, JSContext* context,
+ JS::HandleObject global_object) {
DCHECK(!interface_data->prototype);
DCHECK(!interface_data->interface_object);
+ DCHECK(JS_IsGlobalObject(global_object));
- MozjsGlobalObjectProxy* global_object_proxy =
- static_cast<MozjsGlobalObjectProxy*>(JS_GetContextPrivate(context));
- JS::RootedObject global_object(context, global_object_proxy->global_object());
- DCHECK(global_object);
JS::RootedObject parent_prototype(
context, JS_GetObjectPrototype(context, global_object));
DCHECK(parent_prototype);
@@ -348,8 +367,11 @@
// static
JSObject* MozjsBaseInterface::CreateProxy(
JSContext* context, const scoped_refptr<Wrappable>& wrappable) {
+ JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+ DCHECK(global_object);
+
InterfaceData* interface_data = GetInterfaceData(context);
- JS::RootedObject prototype(context, GetPrototype(context));
+ JS::RootedObject prototype(context, GetPrototype(context, global_object));
DCHECK(prototype);
JS::RootedObject new_object(context, JS_NewObjectWithGivenProto(
context, &interface_data->instance_class_definition, prototype, NULL));
@@ -357,34 +379,45 @@
JS::RootedObject proxy(context,
ProxyHandler::NewProxy(context, new_object, prototype, NULL,
proxy_handler.Pointer()));
- WrapperPrivate::AddPrivateData(proxy, wrappable);
+ WrapperPrivate::AddPrivateData(context, proxy, wrappable);
return proxy;
}
//static
const JSClass* MozjsBaseInterface::PrototypeClass(
JSContext* context) {
- JS::RootedObject prototype(context, GetPrototype(context));
+ JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+ DCHECK(global_object);
+
+ JS::RootedObject prototype(context, GetPrototype(context, global_object));
JSClass* proto_class = JS_GetClass(*prototype.address());
return proto_class;
}
// static
-JSObject* MozjsBaseInterface::GetPrototype(JSContext* context) {
+JSObject* MozjsBaseInterface::GetPrototype(
+ JSContext* context, JS::HandleObject global_object) {
+ DCHECK(JS_IsGlobalObject(global_object));
+
InterfaceData* interface_data = GetInterfaceData(context);
if (!interface_data->prototype) {
// Create new prototype that has all the props and methods
- InitializePrototypeAndInterfaceObject(interface_data, context);
+ InitializePrototypeAndInterfaceObject(
+ interface_data, context, global_object);
}
DCHECK(interface_data->prototype);
return interface_data->prototype;
}
// static
-JSObject* MozjsBaseInterface::GetInterfaceObject(JSContext* context) {
+JSObject* MozjsBaseInterface::GetInterfaceObject(
+ JSContext* context, JS::HandleObject global_object) {
+ DCHECK(JS_IsGlobalObject(global_object));
+
InterfaceData* interface_data = GetInterfaceData(context);
if (!interface_data->interface_object) {
- InitializePrototypeAndInterfaceObject(interface_data, context);
+ InitializePrototypeAndInterfaceObject(
+ interface_data, context, global_object);
}
DCHECK(interface_data->interface_object);
return interface_data->interface_object;
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsBaseInterface.h b/src/cobalt/bindings/generated/mozjs/testing/MozjsBaseInterface.h
index 6a9f2c0..2312b77 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsBaseInterface.h
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsBaseInterface.h
@@ -41,8 +41,10 @@
static JSObject* CreateProxy(JSContext* context,
const scoped_refptr<script::Wrappable>& wrappable);
static const JSClass* PrototypeClass(JSContext* context);
- static JSObject* GetPrototype(JSContext* context);
- static JSObject* GetInterfaceObject(JSContext* context);
+ static JSObject* GetPrototype(JSContext* context,
+ JS::HandleObject global_object);
+ static JSObject* GetInterfaceObject(JSContext* context,
+ JS::HandleObject global_object);
};
} // namespace bindings
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsBooleanTypeTestInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsBooleanTypeTestInterface.cc
index b334f88..86e82f3 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsBooleanTypeTestInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsBooleanTypeTestInterface.cc
@@ -114,6 +114,26 @@
static base::LazyInstance<MozjsBooleanTypeTestInterfaceHandler>
proxy_handler;
+JSBool HasInstance(JSContext *context, JS::HandleObject type,
+ JS::MutableHandleValue vp, JSBool *success) {
+ JS::RootedObject global_object(
+ context, JS_GetGlobalForObject(context, type));
+ DCHECK(global_object);
+
+ JS::RootedObject prototype(
+ context, MozjsBooleanTypeTestInterface::GetPrototype(context, global_object));
+
+ // |IsDelegate| walks the prototype chain of an object returning true if
+ // .prototype is found.
+ bool is_delegate;
+ if (!IsDelegate(context, prototype, vp, &is_delegate)) {
+ *success = false;
+ return false;
+ }
+
+ *success = is_delegate;
+ return true;
+}
InterfaceData* CreateCachedInterfaceData() {
InterfaceData* interface_data = new InterfaceData();
@@ -162,6 +182,7 @@
interface_object_class->enumerate = JS_EnumerateStub;
interface_object_class->resolve = JS_ResolveStub;
interface_object_class->convert = JS_ConvertStub;
+ interface_object_class->hasInstance = &HasInstance;
return interface_data;
}
@@ -332,14 +353,12 @@
};
void InitializePrototypeAndInterfaceObject(
- InterfaceData* interface_data, JSContext* context) {
+ InterfaceData* interface_data, JSContext* context,
+ JS::HandleObject global_object) {
DCHECK(!interface_data->prototype);
DCHECK(!interface_data->interface_object);
+ DCHECK(JS_IsGlobalObject(global_object));
- MozjsGlobalObjectProxy* global_object_proxy =
- static_cast<MozjsGlobalObjectProxy*>(JS_GetContextPrivate(context));
- JS::RootedObject global_object(context, global_object_proxy->global_object());
- DCHECK(global_object);
JS::RootedObject parent_prototype(
context, JS_GetObjectPrototype(context, global_object));
DCHECK(parent_prototype);
@@ -418,8 +437,11 @@
// static
JSObject* MozjsBooleanTypeTestInterface::CreateProxy(
JSContext* context, const scoped_refptr<Wrappable>& wrappable) {
+ JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+ DCHECK(global_object);
+
InterfaceData* interface_data = GetInterfaceData(context);
- JS::RootedObject prototype(context, GetPrototype(context));
+ JS::RootedObject prototype(context, GetPrototype(context, global_object));
DCHECK(prototype);
JS::RootedObject new_object(context, JS_NewObjectWithGivenProto(
context, &interface_data->instance_class_definition, prototype, NULL));
@@ -427,34 +449,45 @@
JS::RootedObject proxy(context,
ProxyHandler::NewProxy(context, new_object, prototype, NULL,
proxy_handler.Pointer()));
- WrapperPrivate::AddPrivateData(proxy, wrappable);
+ WrapperPrivate::AddPrivateData(context, proxy, wrappable);
return proxy;
}
//static
const JSClass* MozjsBooleanTypeTestInterface::PrototypeClass(
JSContext* context) {
- JS::RootedObject prototype(context, GetPrototype(context));
+ JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+ DCHECK(global_object);
+
+ JS::RootedObject prototype(context, GetPrototype(context, global_object));
JSClass* proto_class = JS_GetClass(*prototype.address());
return proto_class;
}
// static
-JSObject* MozjsBooleanTypeTestInterface::GetPrototype(JSContext* context) {
+JSObject* MozjsBooleanTypeTestInterface::GetPrototype(
+ JSContext* context, JS::HandleObject global_object) {
+ DCHECK(JS_IsGlobalObject(global_object));
+
InterfaceData* interface_data = GetInterfaceData(context);
if (!interface_data->prototype) {
// Create new prototype that has all the props and methods
- InitializePrototypeAndInterfaceObject(interface_data, context);
+ InitializePrototypeAndInterfaceObject(
+ interface_data, context, global_object);
}
DCHECK(interface_data->prototype);
return interface_data->prototype;
}
// static
-JSObject* MozjsBooleanTypeTestInterface::GetInterfaceObject(JSContext* context) {
+JSObject* MozjsBooleanTypeTestInterface::GetInterfaceObject(
+ JSContext* context, JS::HandleObject global_object) {
+ DCHECK(JS_IsGlobalObject(global_object));
+
InterfaceData* interface_data = GetInterfaceData(context);
if (!interface_data->interface_object) {
- InitializePrototypeAndInterfaceObject(interface_data, context);
+ InitializePrototypeAndInterfaceObject(
+ interface_data, context, global_object);
}
DCHECK(interface_data->interface_object);
return interface_data->interface_object;
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsBooleanTypeTestInterface.h b/src/cobalt/bindings/generated/mozjs/testing/MozjsBooleanTypeTestInterface.h
index d240a38..fa3f0e3 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsBooleanTypeTestInterface.h
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsBooleanTypeTestInterface.h
@@ -41,8 +41,10 @@
static JSObject* CreateProxy(JSContext* context,
const scoped_refptr<script::Wrappable>& wrappable);
static const JSClass* PrototypeClass(JSContext* context);
- static JSObject* GetPrototype(JSContext* context);
- static JSObject* GetInterfaceObject(JSContext* context);
+ static JSObject* GetPrototype(JSContext* context,
+ JS::HandleObject global_object);
+ static JSObject* GetInterfaceObject(JSContext* context,
+ JS::HandleObject global_object);
};
} // namespace bindings
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsCallbackFunctionInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsCallbackFunctionInterface.cc
index a6360ce..379afa8 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsCallbackFunctionInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsCallbackFunctionInterface.cc
@@ -118,6 +118,26 @@
static base::LazyInstance<MozjsCallbackFunctionInterfaceHandler>
proxy_handler;
+JSBool HasInstance(JSContext *context, JS::HandleObject type,
+ JS::MutableHandleValue vp, JSBool *success) {
+ JS::RootedObject global_object(
+ context, JS_GetGlobalForObject(context, type));
+ DCHECK(global_object);
+
+ JS::RootedObject prototype(
+ context, MozjsCallbackFunctionInterface::GetPrototype(context, global_object));
+
+ // |IsDelegate| walks the prototype chain of an object returning true if
+ // .prototype is found.
+ bool is_delegate;
+ if (!IsDelegate(context, prototype, vp, &is_delegate)) {
+ *success = false;
+ return false;
+ }
+
+ *success = is_delegate;
+ return true;
+}
InterfaceData* CreateCachedInterfaceData() {
InterfaceData* interface_data = new InterfaceData();
@@ -166,6 +186,7 @@
interface_object_class->enumerate = JS_EnumerateStub;
interface_object_class->resolve = JS_ResolveStub;
interface_object_class->convert = JS_ConvertStub;
+ interface_object_class->hasInstance = &HasInstance;
return interface_data;
}
@@ -561,14 +582,12 @@
};
void InitializePrototypeAndInterfaceObject(
- InterfaceData* interface_data, JSContext* context) {
+ InterfaceData* interface_data, JSContext* context,
+ JS::HandleObject global_object) {
DCHECK(!interface_data->prototype);
DCHECK(!interface_data->interface_object);
+ DCHECK(JS_IsGlobalObject(global_object));
- MozjsGlobalObjectProxy* global_object_proxy =
- static_cast<MozjsGlobalObjectProxy*>(JS_GetContextPrivate(context));
- JS::RootedObject global_object(context, global_object_proxy->global_object());
- DCHECK(global_object);
JS::RootedObject parent_prototype(
context, JS_GetObjectPrototype(context, global_object));
DCHECK(parent_prototype);
@@ -647,8 +666,11 @@
// static
JSObject* MozjsCallbackFunctionInterface::CreateProxy(
JSContext* context, const scoped_refptr<Wrappable>& wrappable) {
+ JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+ DCHECK(global_object);
+
InterfaceData* interface_data = GetInterfaceData(context);
- JS::RootedObject prototype(context, GetPrototype(context));
+ JS::RootedObject prototype(context, GetPrototype(context, global_object));
DCHECK(prototype);
JS::RootedObject new_object(context, JS_NewObjectWithGivenProto(
context, &interface_data->instance_class_definition, prototype, NULL));
@@ -656,34 +678,45 @@
JS::RootedObject proxy(context,
ProxyHandler::NewProxy(context, new_object, prototype, NULL,
proxy_handler.Pointer()));
- WrapperPrivate::AddPrivateData(proxy, wrappable);
+ WrapperPrivate::AddPrivateData(context, proxy, wrappable);
return proxy;
}
//static
const JSClass* MozjsCallbackFunctionInterface::PrototypeClass(
JSContext* context) {
- JS::RootedObject prototype(context, GetPrototype(context));
+ JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+ DCHECK(global_object);
+
+ JS::RootedObject prototype(context, GetPrototype(context, global_object));
JSClass* proto_class = JS_GetClass(*prototype.address());
return proto_class;
}
// static
-JSObject* MozjsCallbackFunctionInterface::GetPrototype(JSContext* context) {
+JSObject* MozjsCallbackFunctionInterface::GetPrototype(
+ JSContext* context, JS::HandleObject global_object) {
+ DCHECK(JS_IsGlobalObject(global_object));
+
InterfaceData* interface_data = GetInterfaceData(context);
if (!interface_data->prototype) {
// Create new prototype that has all the props and methods
- InitializePrototypeAndInterfaceObject(interface_data, context);
+ InitializePrototypeAndInterfaceObject(
+ interface_data, context, global_object);
}
DCHECK(interface_data->prototype);
return interface_data->prototype;
}
// static
-JSObject* MozjsCallbackFunctionInterface::GetInterfaceObject(JSContext* context) {
+JSObject* MozjsCallbackFunctionInterface::GetInterfaceObject(
+ JSContext* context, JS::HandleObject global_object) {
+ DCHECK(JS_IsGlobalObject(global_object));
+
InterfaceData* interface_data = GetInterfaceData(context);
if (!interface_data->interface_object) {
- InitializePrototypeAndInterfaceObject(interface_data, context);
+ InitializePrototypeAndInterfaceObject(
+ interface_data, context, global_object);
}
DCHECK(interface_data->interface_object);
return interface_data->interface_object;
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsCallbackFunctionInterface.h b/src/cobalt/bindings/generated/mozjs/testing/MozjsCallbackFunctionInterface.h
index e85e0f2..dea49b2 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsCallbackFunctionInterface.h
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsCallbackFunctionInterface.h
@@ -41,8 +41,10 @@
static JSObject* CreateProxy(JSContext* context,
const scoped_refptr<script::Wrappable>& wrappable);
static const JSClass* PrototypeClass(JSContext* context);
- static JSObject* GetPrototype(JSContext* context);
- static JSObject* GetInterfaceObject(JSContext* context);
+ static JSObject* GetPrototype(JSContext* context,
+ JS::HandleObject global_object);
+ static JSObject* GetInterfaceObject(JSContext* context,
+ JS::HandleObject global_object);
};
} // namespace bindings
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsCallbackInterfaceInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsCallbackInterfaceInterface.cc
index 3a9b54c..b387cf6 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsCallbackInterfaceInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsCallbackInterfaceInterface.cc
@@ -118,6 +118,26 @@
static base::LazyInstance<MozjsCallbackInterfaceInterfaceHandler>
proxy_handler;
+JSBool HasInstance(JSContext *context, JS::HandleObject type,
+ JS::MutableHandleValue vp, JSBool *success) {
+ JS::RootedObject global_object(
+ context, JS_GetGlobalForObject(context, type));
+ DCHECK(global_object);
+
+ JS::RootedObject prototype(
+ context, MozjsCallbackInterfaceInterface::GetPrototype(context, global_object));
+
+ // |IsDelegate| walks the prototype chain of an object returning true if
+ // .prototype is found.
+ bool is_delegate;
+ if (!IsDelegate(context, prototype, vp, &is_delegate)) {
+ *success = false;
+ return false;
+ }
+
+ *success = is_delegate;
+ return true;
+}
InterfaceData* CreateCachedInterfaceData() {
InterfaceData* interface_data = new InterfaceData();
@@ -166,6 +186,7 @@
interface_object_class->enumerate = JS_EnumerateStub;
interface_object_class->resolve = JS_ResolveStub;
interface_object_class->convert = JS_ConvertStub;
+ interface_object_class->hasInstance = &HasInstance;
return interface_data;
}
@@ -330,14 +351,12 @@
};
void InitializePrototypeAndInterfaceObject(
- InterfaceData* interface_data, JSContext* context) {
+ InterfaceData* interface_data, JSContext* context,
+ JS::HandleObject global_object) {
DCHECK(!interface_data->prototype);
DCHECK(!interface_data->interface_object);
+ DCHECK(JS_IsGlobalObject(global_object));
- MozjsGlobalObjectProxy* global_object_proxy =
- static_cast<MozjsGlobalObjectProxy*>(JS_GetContextPrivate(context));
- JS::RootedObject global_object(context, global_object_proxy->global_object());
- DCHECK(global_object);
JS::RootedObject parent_prototype(
context, JS_GetObjectPrototype(context, global_object));
DCHECK(parent_prototype);
@@ -416,8 +435,11 @@
// static
JSObject* MozjsCallbackInterfaceInterface::CreateProxy(
JSContext* context, const scoped_refptr<Wrappable>& wrappable) {
+ JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+ DCHECK(global_object);
+
InterfaceData* interface_data = GetInterfaceData(context);
- JS::RootedObject prototype(context, GetPrototype(context));
+ JS::RootedObject prototype(context, GetPrototype(context, global_object));
DCHECK(prototype);
JS::RootedObject new_object(context, JS_NewObjectWithGivenProto(
context, &interface_data->instance_class_definition, prototype, NULL));
@@ -425,34 +447,45 @@
JS::RootedObject proxy(context,
ProxyHandler::NewProxy(context, new_object, prototype, NULL,
proxy_handler.Pointer()));
- WrapperPrivate::AddPrivateData(proxy, wrappable);
+ WrapperPrivate::AddPrivateData(context, proxy, wrappable);
return proxy;
}
//static
const JSClass* MozjsCallbackInterfaceInterface::PrototypeClass(
JSContext* context) {
- JS::RootedObject prototype(context, GetPrototype(context));
+ JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+ DCHECK(global_object);
+
+ JS::RootedObject prototype(context, GetPrototype(context, global_object));
JSClass* proto_class = JS_GetClass(*prototype.address());
return proto_class;
}
// static
-JSObject* MozjsCallbackInterfaceInterface::GetPrototype(JSContext* context) {
+JSObject* MozjsCallbackInterfaceInterface::GetPrototype(
+ JSContext* context, JS::HandleObject global_object) {
+ DCHECK(JS_IsGlobalObject(global_object));
+
InterfaceData* interface_data = GetInterfaceData(context);
if (!interface_data->prototype) {
// Create new prototype that has all the props and methods
- InitializePrototypeAndInterfaceObject(interface_data, context);
+ InitializePrototypeAndInterfaceObject(
+ interface_data, context, global_object);
}
DCHECK(interface_data->prototype);
return interface_data->prototype;
}
// static
-JSObject* MozjsCallbackInterfaceInterface::GetInterfaceObject(JSContext* context) {
+JSObject* MozjsCallbackInterfaceInterface::GetInterfaceObject(
+ JSContext* context, JS::HandleObject global_object) {
+ DCHECK(JS_IsGlobalObject(global_object));
+
InterfaceData* interface_data = GetInterfaceData(context);
if (!interface_data->interface_object) {
- InitializePrototypeAndInterfaceObject(interface_data, context);
+ InitializePrototypeAndInterfaceObject(
+ interface_data, context, global_object);
}
DCHECK(interface_data->interface_object);
return interface_data->interface_object;
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsCallbackInterfaceInterface.h b/src/cobalt/bindings/generated/mozjs/testing/MozjsCallbackInterfaceInterface.h
index ea10dca..788a86f 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsCallbackInterfaceInterface.h
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsCallbackInterfaceInterface.h
@@ -41,8 +41,10 @@
static JSObject* CreateProxy(JSContext* context,
const scoped_refptr<script::Wrappable>& wrappable);
static const JSClass* PrototypeClass(JSContext* context);
- static JSObject* GetPrototype(JSContext* context);
- static JSObject* GetInterfaceObject(JSContext* context);
+ static JSObject* GetPrototype(JSContext* context,
+ JS::HandleObject global_object);
+ static JSObject* GetInterfaceObject(JSContext* context,
+ JS::HandleObject global_object);
};
} // namespace bindings
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsConditionalInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsConditionalInterface.cc
index eae8530..dcf4ed6 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsConditionalInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsConditionalInterface.cc
@@ -116,6 +116,26 @@
static base::LazyInstance<MozjsConditionalInterfaceHandler>
proxy_handler;
+JSBool HasInstance(JSContext *context, JS::HandleObject type,
+ JS::MutableHandleValue vp, JSBool *success) {
+ JS::RootedObject global_object(
+ context, JS_GetGlobalForObject(context, type));
+ DCHECK(global_object);
+
+ JS::RootedObject prototype(
+ context, MozjsConditionalInterface::GetPrototype(context, global_object));
+
+ // |IsDelegate| walks the prototype chain of an object returning true if
+ // .prototype is found.
+ bool is_delegate;
+ if (!IsDelegate(context, prototype, vp, &is_delegate)) {
+ *success = false;
+ return false;
+ }
+
+ *success = is_delegate;
+ return true;
+}
InterfaceData* CreateCachedInterfaceData() {
InterfaceData* interface_data = new InterfaceData();
@@ -164,6 +184,7 @@
interface_object_class->enumerate = JS_EnumerateStub;
interface_object_class->resolve = JS_ResolveStub;
interface_object_class->convert = JS_ConvertStub;
+ interface_object_class->hasInstance = &HasInstance;
return interface_data;
}
@@ -375,14 +396,12 @@
};
void InitializePrototypeAndInterfaceObject(
- InterfaceData* interface_data, JSContext* context) {
+ InterfaceData* interface_data, JSContext* context,
+ JS::HandleObject global_object) {
DCHECK(!interface_data->prototype);
DCHECK(!interface_data->interface_object);
+ DCHECK(JS_IsGlobalObject(global_object));
- MozjsGlobalObjectProxy* global_object_proxy =
- static_cast<MozjsGlobalObjectProxy*>(JS_GetContextPrivate(context));
- JS::RootedObject global_object(context, global_object_proxy->global_object());
- DCHECK(global_object);
JS::RootedObject parent_prototype(
context, JS_GetObjectPrototype(context, global_object));
DCHECK(parent_prototype);
@@ -461,8 +480,11 @@
// static
JSObject* MozjsConditionalInterface::CreateProxy(
JSContext* context, const scoped_refptr<Wrappable>& wrappable) {
+ JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+ DCHECK(global_object);
+
InterfaceData* interface_data = GetInterfaceData(context);
- JS::RootedObject prototype(context, GetPrototype(context));
+ JS::RootedObject prototype(context, GetPrototype(context, global_object));
DCHECK(prototype);
JS::RootedObject new_object(context, JS_NewObjectWithGivenProto(
context, &interface_data->instance_class_definition, prototype, NULL));
@@ -470,34 +492,45 @@
JS::RootedObject proxy(context,
ProxyHandler::NewProxy(context, new_object, prototype, NULL,
proxy_handler.Pointer()));
- WrapperPrivate::AddPrivateData(proxy, wrappable);
+ WrapperPrivate::AddPrivateData(context, proxy, wrappable);
return proxy;
}
//static
const JSClass* MozjsConditionalInterface::PrototypeClass(
JSContext* context) {
- JS::RootedObject prototype(context, GetPrototype(context));
+ JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+ DCHECK(global_object);
+
+ JS::RootedObject prototype(context, GetPrototype(context, global_object));
JSClass* proto_class = JS_GetClass(*prototype.address());
return proto_class;
}
// static
-JSObject* MozjsConditionalInterface::GetPrototype(JSContext* context) {
+JSObject* MozjsConditionalInterface::GetPrototype(
+ JSContext* context, JS::HandleObject global_object) {
+ DCHECK(JS_IsGlobalObject(global_object));
+
InterfaceData* interface_data = GetInterfaceData(context);
if (!interface_data->prototype) {
// Create new prototype that has all the props and methods
- InitializePrototypeAndInterfaceObject(interface_data, context);
+ InitializePrototypeAndInterfaceObject(
+ interface_data, context, global_object);
}
DCHECK(interface_data->prototype);
return interface_data->prototype;
}
// static
-JSObject* MozjsConditionalInterface::GetInterfaceObject(JSContext* context) {
+JSObject* MozjsConditionalInterface::GetInterfaceObject(
+ JSContext* context, JS::HandleObject global_object) {
+ DCHECK(JS_IsGlobalObject(global_object));
+
InterfaceData* interface_data = GetInterfaceData(context);
if (!interface_data->interface_object) {
- InitializePrototypeAndInterfaceObject(interface_data, context);
+ InitializePrototypeAndInterfaceObject(
+ interface_data, context, global_object);
}
DCHECK(interface_data->interface_object);
return interface_data->interface_object;
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsConditionalInterface.h b/src/cobalt/bindings/generated/mozjs/testing/MozjsConditionalInterface.h
index 76eae81..ea935c1 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsConditionalInterface.h
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsConditionalInterface.h
@@ -43,8 +43,10 @@
static JSObject* CreateProxy(JSContext* context,
const scoped_refptr<script::Wrappable>& wrappable);
static const JSClass* PrototypeClass(JSContext* context);
- static JSObject* GetPrototype(JSContext* context);
- static JSObject* GetInterfaceObject(JSContext* context);
+ static JSObject* GetPrototype(JSContext* context,
+ JS::HandleObject global_object);
+ static JSObject* GetInterfaceObject(JSContext* context,
+ JS::HandleObject global_object);
};
} // namespace bindings
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsConstantsInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsConstantsInterface.cc
index 06ca83e..467b6de 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsConstantsInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsConstantsInterface.cc
@@ -143,6 +143,26 @@
return !exception_state.is_exception_set();
}
+JSBool HasInstance(JSContext *context, JS::HandleObject type,
+ JS::MutableHandleValue vp, JSBool *success) {
+ JS::RootedObject global_object(
+ context, JS_GetGlobalForObject(context, type));
+ DCHECK(global_object);
+
+ JS::RootedObject prototype(
+ context, MozjsConstantsInterface::GetPrototype(context, global_object));
+
+ // |IsDelegate| walks the prototype chain of an object returning true if
+ // .prototype is found.
+ bool is_delegate;
+ if (!IsDelegate(context, prototype, vp, &is_delegate)) {
+ *success = false;
+ return false;
+ }
+
+ *success = is_delegate;
+ return true;
+}
InterfaceData* CreateCachedInterfaceData() {
InterfaceData* interface_data = new InterfaceData();
@@ -191,6 +211,7 @@
interface_object_class->enumerate = JS_EnumerateStub;
interface_object_class->resolve = JS_ResolveStub;
interface_object_class->convert = JS_ConvertStub;
+ interface_object_class->hasInstance = &HasInstance;
return interface_data;
}
@@ -240,14 +261,12 @@
};
void InitializePrototypeAndInterfaceObject(
- InterfaceData* interface_data, JSContext* context) {
+ InterfaceData* interface_data, JSContext* context,
+ JS::HandleObject global_object) {
DCHECK(!interface_data->prototype);
DCHECK(!interface_data->interface_object);
+ DCHECK(JS_IsGlobalObject(global_object));
- MozjsGlobalObjectProxy* global_object_proxy =
- static_cast<MozjsGlobalObjectProxy*>(JS_GetContextPrivate(context));
- JS::RootedObject global_object(context, global_object_proxy->global_object());
- DCHECK(global_object);
JS::RootedObject parent_prototype(
context, JS_GetObjectPrototype(context, global_object));
DCHECK(parent_prototype);
@@ -326,8 +345,11 @@
// static
JSObject* MozjsConstantsInterface::CreateProxy(
JSContext* context, const scoped_refptr<Wrappable>& wrappable) {
+ JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+ DCHECK(global_object);
+
InterfaceData* interface_data = GetInterfaceData(context);
- JS::RootedObject prototype(context, GetPrototype(context));
+ JS::RootedObject prototype(context, GetPrototype(context, global_object));
DCHECK(prototype);
JS::RootedObject new_object(context, JS_NewObjectWithGivenProto(
context, &interface_data->instance_class_definition, prototype, NULL));
@@ -335,34 +357,45 @@
JS::RootedObject proxy(context,
ProxyHandler::NewProxy(context, new_object, prototype, NULL,
proxy_handler.Pointer()));
- WrapperPrivate::AddPrivateData(proxy, wrappable);
+ WrapperPrivate::AddPrivateData(context, proxy, wrappable);
return proxy;
}
//static
const JSClass* MozjsConstantsInterface::PrototypeClass(
JSContext* context) {
- JS::RootedObject prototype(context, GetPrototype(context));
+ JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+ DCHECK(global_object);
+
+ JS::RootedObject prototype(context, GetPrototype(context, global_object));
JSClass* proto_class = JS_GetClass(*prototype.address());
return proto_class;
}
// static
-JSObject* MozjsConstantsInterface::GetPrototype(JSContext* context) {
+JSObject* MozjsConstantsInterface::GetPrototype(
+ JSContext* context, JS::HandleObject global_object) {
+ DCHECK(JS_IsGlobalObject(global_object));
+
InterfaceData* interface_data = GetInterfaceData(context);
if (!interface_data->prototype) {
// Create new prototype that has all the props and methods
- InitializePrototypeAndInterfaceObject(interface_data, context);
+ InitializePrototypeAndInterfaceObject(
+ interface_data, context, global_object);
}
DCHECK(interface_data->prototype);
return interface_data->prototype;
}
// static
-JSObject* MozjsConstantsInterface::GetInterfaceObject(JSContext* context) {
+JSObject* MozjsConstantsInterface::GetInterfaceObject(
+ JSContext* context, JS::HandleObject global_object) {
+ DCHECK(JS_IsGlobalObject(global_object));
+
InterfaceData* interface_data = GetInterfaceData(context);
if (!interface_data->interface_object) {
- InitializePrototypeAndInterfaceObject(interface_data, context);
+ InitializePrototypeAndInterfaceObject(
+ interface_data, context, global_object);
}
DCHECK(interface_data->interface_object);
return interface_data->interface_object;
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsConstantsInterface.h b/src/cobalt/bindings/generated/mozjs/testing/MozjsConstantsInterface.h
index fe793ef..3501f0f 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsConstantsInterface.h
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsConstantsInterface.h
@@ -41,8 +41,10 @@
static JSObject* CreateProxy(JSContext* context,
const scoped_refptr<script::Wrappable>& wrappable);
static const JSClass* PrototypeClass(JSContext* context);
- static JSObject* GetPrototype(JSContext* context);
- static JSObject* GetInterfaceObject(JSContext* context);
+ static JSObject* GetPrototype(JSContext* context,
+ JS::HandleObject global_object);
+ static JSObject* GetInterfaceObject(JSContext* context,
+ JS::HandleObject global_object);
};
} // namespace bindings
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsConstructorInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsConstructorInterface.cc
index 7ca19b8..8367aeb 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsConstructorInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsConstructorInterface.cc
@@ -115,6 +115,26 @@
proxy_handler;
JSBool Constructor(JSContext* context, unsigned int argc, JS::Value* vp);
+JSBool HasInstance(JSContext *context, JS::HandleObject type,
+ JS::MutableHandleValue vp, JSBool *success) {
+ JS::RootedObject global_object(
+ context, JS_GetGlobalForObject(context, type));
+ DCHECK(global_object);
+
+ JS::RootedObject prototype(
+ context, MozjsConstructorInterface::GetPrototype(context, global_object));
+
+ // |IsDelegate| walks the prototype chain of an object returning true if
+ // .prototype is found.
+ bool is_delegate;
+ if (!IsDelegate(context, prototype, vp, &is_delegate)) {
+ *success = false;
+ return false;
+ }
+
+ *success = is_delegate;
+ return true;
+}
InterfaceData* CreateCachedInterfaceData() {
InterfaceData* interface_data = new InterfaceData();
@@ -163,6 +183,7 @@
interface_object_class->enumerate = JS_EnumerateStub;
interface_object_class->resolve = JS_ResolveStub;
interface_object_class->convert = JS_ConvertStub;
+ interface_object_class->hasInstance = &HasInstance;
interface_object_class->construct = Constructor;
return interface_data;
}
@@ -189,14 +210,12 @@
};
void InitializePrototypeAndInterfaceObject(
- InterfaceData* interface_data, JSContext* context) {
+ InterfaceData* interface_data, JSContext* context,
+ JS::HandleObject global_object) {
DCHECK(!interface_data->prototype);
DCHECK(!interface_data->interface_object);
+ DCHECK(JS_IsGlobalObject(global_object));
- MozjsGlobalObjectProxy* global_object_proxy =
- static_cast<MozjsGlobalObjectProxy*>(JS_GetContextPrivate(context));
- JS::RootedObject global_object(context, global_object_proxy->global_object());
- DCHECK(global_object);
JS::RootedObject parent_prototype(
context, JS_GetObjectPrototype(context, global_object));
DCHECK(parent_prototype);
@@ -285,8 +304,11 @@
// static
JSObject* MozjsConstructorInterface::CreateProxy(
JSContext* context, const scoped_refptr<Wrappable>& wrappable) {
+ JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+ DCHECK(global_object);
+
InterfaceData* interface_data = GetInterfaceData(context);
- JS::RootedObject prototype(context, GetPrototype(context));
+ JS::RootedObject prototype(context, GetPrototype(context, global_object));
DCHECK(prototype);
JS::RootedObject new_object(context, JS_NewObjectWithGivenProto(
context, &interface_data->instance_class_definition, prototype, NULL));
@@ -294,34 +316,45 @@
JS::RootedObject proxy(context,
ProxyHandler::NewProxy(context, new_object, prototype, NULL,
proxy_handler.Pointer()));
- WrapperPrivate::AddPrivateData(proxy, wrappable);
+ WrapperPrivate::AddPrivateData(context, proxy, wrappable);
return proxy;
}
//static
const JSClass* MozjsConstructorInterface::PrototypeClass(
JSContext* context) {
- JS::RootedObject prototype(context, GetPrototype(context));
+ JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+ DCHECK(global_object);
+
+ JS::RootedObject prototype(context, GetPrototype(context, global_object));
JSClass* proto_class = JS_GetClass(*prototype.address());
return proto_class;
}
// static
-JSObject* MozjsConstructorInterface::GetPrototype(JSContext* context) {
+JSObject* MozjsConstructorInterface::GetPrototype(
+ JSContext* context, JS::HandleObject global_object) {
+ DCHECK(JS_IsGlobalObject(global_object));
+
InterfaceData* interface_data = GetInterfaceData(context);
if (!interface_data->prototype) {
// Create new prototype that has all the props and methods
- InitializePrototypeAndInterfaceObject(interface_data, context);
+ InitializePrototypeAndInterfaceObject(
+ interface_data, context, global_object);
}
DCHECK(interface_data->prototype);
return interface_data->prototype;
}
// static
-JSObject* MozjsConstructorInterface::GetInterfaceObject(JSContext* context) {
+JSObject* MozjsConstructorInterface::GetInterfaceObject(
+ JSContext* context, JS::HandleObject global_object) {
+ DCHECK(JS_IsGlobalObject(global_object));
+
InterfaceData* interface_data = GetInterfaceData(context);
if (!interface_data->interface_object) {
- InitializePrototypeAndInterfaceObject(interface_data, context);
+ InitializePrototypeAndInterfaceObject(
+ interface_data, context, global_object);
}
DCHECK(interface_data->interface_object);
return interface_data->interface_object;
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsConstructorInterface.h b/src/cobalt/bindings/generated/mozjs/testing/MozjsConstructorInterface.h
index d04a69f..ccf6f57 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsConstructorInterface.h
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsConstructorInterface.h
@@ -41,8 +41,10 @@
static JSObject* CreateProxy(JSContext* context,
const scoped_refptr<script::Wrappable>& wrappable);
static const JSClass* PrototypeClass(JSContext* context);
- static JSObject* GetPrototype(JSContext* context);
- static JSObject* GetInterfaceObject(JSContext* context);
+ static JSObject* GetPrototype(JSContext* context,
+ JS::HandleObject global_object);
+ static JSObject* GetInterfaceObject(JSContext* context,
+ JS::HandleObject global_object);
};
} // namespace bindings
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsConstructorWithArgumentsInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsConstructorWithArgumentsInterface.cc
index cdc6b94..bcf7385 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsConstructorWithArgumentsInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsConstructorWithArgumentsInterface.cc
@@ -115,6 +115,26 @@
proxy_handler;
JSBool Constructor(JSContext* context, unsigned int argc, JS::Value* vp);
+JSBool HasInstance(JSContext *context, JS::HandleObject type,
+ JS::MutableHandleValue vp, JSBool *success) {
+ JS::RootedObject global_object(
+ context, JS_GetGlobalForObject(context, type));
+ DCHECK(global_object);
+
+ JS::RootedObject prototype(
+ context, MozjsConstructorWithArgumentsInterface::GetPrototype(context, global_object));
+
+ // |IsDelegate| walks the prototype chain of an object returning true if
+ // .prototype is found.
+ bool is_delegate;
+ if (!IsDelegate(context, prototype, vp, &is_delegate)) {
+ *success = false;
+ return false;
+ }
+
+ *success = is_delegate;
+ return true;
+}
InterfaceData* CreateCachedInterfaceData() {
InterfaceData* interface_data = new InterfaceData();
@@ -163,6 +183,7 @@
interface_object_class->enumerate = JS_EnumerateStub;
interface_object_class->resolve = JS_ResolveStub;
interface_object_class->convert = JS_ConvertStub;
+ interface_object_class->hasInstance = &HasInstance;
interface_object_class->construct = Constructor;
return interface_data;
}
@@ -273,14 +294,12 @@
};
void InitializePrototypeAndInterfaceObject(
- InterfaceData* interface_data, JSContext* context) {
+ InterfaceData* interface_data, JSContext* context,
+ JS::HandleObject global_object) {
DCHECK(!interface_data->prototype);
DCHECK(!interface_data->interface_object);
+ DCHECK(JS_IsGlobalObject(global_object));
- MozjsGlobalObjectProxy* global_object_proxy =
- static_cast<MozjsGlobalObjectProxy*>(JS_GetContextPrivate(context));
- JS::RootedObject global_object(context, global_object_proxy->global_object());
- DCHECK(global_object);
JS::RootedObject parent_prototype(
context, JS_GetObjectPrototype(context, global_object));
DCHECK(parent_prototype);
@@ -369,8 +388,11 @@
// static
JSObject* MozjsConstructorWithArgumentsInterface::CreateProxy(
JSContext* context, const scoped_refptr<Wrappable>& wrappable) {
+ JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+ DCHECK(global_object);
+
InterfaceData* interface_data = GetInterfaceData(context);
- JS::RootedObject prototype(context, GetPrototype(context));
+ JS::RootedObject prototype(context, GetPrototype(context, global_object));
DCHECK(prototype);
JS::RootedObject new_object(context, JS_NewObjectWithGivenProto(
context, &interface_data->instance_class_definition, prototype, NULL));
@@ -378,34 +400,45 @@
JS::RootedObject proxy(context,
ProxyHandler::NewProxy(context, new_object, prototype, NULL,
proxy_handler.Pointer()));
- WrapperPrivate::AddPrivateData(proxy, wrappable);
+ WrapperPrivate::AddPrivateData(context, proxy, wrappable);
return proxy;
}
//static
const JSClass* MozjsConstructorWithArgumentsInterface::PrototypeClass(
JSContext* context) {
- JS::RootedObject prototype(context, GetPrototype(context));
+ JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+ DCHECK(global_object);
+
+ JS::RootedObject prototype(context, GetPrototype(context, global_object));
JSClass* proto_class = JS_GetClass(*prototype.address());
return proto_class;
}
// static
-JSObject* MozjsConstructorWithArgumentsInterface::GetPrototype(JSContext* context) {
+JSObject* MozjsConstructorWithArgumentsInterface::GetPrototype(
+ JSContext* context, JS::HandleObject global_object) {
+ DCHECK(JS_IsGlobalObject(global_object));
+
InterfaceData* interface_data = GetInterfaceData(context);
if (!interface_data->prototype) {
// Create new prototype that has all the props and methods
- InitializePrototypeAndInterfaceObject(interface_data, context);
+ InitializePrototypeAndInterfaceObject(
+ interface_data, context, global_object);
}
DCHECK(interface_data->prototype);
return interface_data->prototype;
}
// static
-JSObject* MozjsConstructorWithArgumentsInterface::GetInterfaceObject(JSContext* context) {
+JSObject* MozjsConstructorWithArgumentsInterface::GetInterfaceObject(
+ JSContext* context, JS::HandleObject global_object) {
+ DCHECK(JS_IsGlobalObject(global_object));
+
InterfaceData* interface_data = GetInterfaceData(context);
if (!interface_data->interface_object) {
- InitializePrototypeAndInterfaceObject(interface_data, context);
+ InitializePrototypeAndInterfaceObject(
+ interface_data, context, global_object);
}
DCHECK(interface_data->interface_object);
return interface_data->interface_object;
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsConstructorWithArgumentsInterface.h b/src/cobalt/bindings/generated/mozjs/testing/MozjsConstructorWithArgumentsInterface.h
index 44d36d4..76c43fc 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsConstructorWithArgumentsInterface.h
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsConstructorWithArgumentsInterface.h
@@ -41,8 +41,10 @@
static JSObject* CreateProxy(JSContext* context,
const scoped_refptr<script::Wrappable>& wrappable);
static const JSClass* PrototypeClass(JSContext* context);
- static JSObject* GetPrototype(JSContext* context);
- static JSObject* GetInterfaceObject(JSContext* context);
+ static JSObject* GetPrototype(JSContext* context,
+ JS::HandleObject global_object);
+ static JSObject* GetInterfaceObject(JSContext* context,
+ JS::HandleObject global_object);
};
} // namespace bindings
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsDOMStringTestInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsDOMStringTestInterface.cc
index bc6eb8b..18dd40a 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsDOMStringTestInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsDOMStringTestInterface.cc
@@ -114,6 +114,26 @@
static base::LazyInstance<MozjsDOMStringTestInterfaceHandler>
proxy_handler;
+JSBool HasInstance(JSContext *context, JS::HandleObject type,
+ JS::MutableHandleValue vp, JSBool *success) {
+ JS::RootedObject global_object(
+ context, JS_GetGlobalForObject(context, type));
+ DCHECK(global_object);
+
+ JS::RootedObject prototype(
+ context, MozjsDOMStringTestInterface::GetPrototype(context, global_object));
+
+ // |IsDelegate| walks the prototype chain of an object returning true if
+ // .prototype is found.
+ bool is_delegate;
+ if (!IsDelegate(context, prototype, vp, &is_delegate)) {
+ *success = false;
+ return false;
+ }
+
+ *success = is_delegate;
+ return true;
+}
InterfaceData* CreateCachedInterfaceData() {
InterfaceData* interface_data = new InterfaceData();
@@ -162,6 +182,7 @@
interface_object_class->enumerate = JS_EnumerateStub;
interface_object_class->resolve = JS_ResolveStub;
interface_object_class->convert = JS_ConvertStub;
+ interface_object_class->hasInstance = &HasInstance;
return interface_data;
}
@@ -443,14 +464,12 @@
};
void InitializePrototypeAndInterfaceObject(
- InterfaceData* interface_data, JSContext* context) {
+ InterfaceData* interface_data, JSContext* context,
+ JS::HandleObject global_object) {
DCHECK(!interface_data->prototype);
DCHECK(!interface_data->interface_object);
+ DCHECK(JS_IsGlobalObject(global_object));
- MozjsGlobalObjectProxy* global_object_proxy =
- static_cast<MozjsGlobalObjectProxy*>(JS_GetContextPrivate(context));
- JS::RootedObject global_object(context, global_object_proxy->global_object());
- DCHECK(global_object);
JS::RootedObject parent_prototype(
context, JS_GetObjectPrototype(context, global_object));
DCHECK(parent_prototype);
@@ -529,8 +548,11 @@
// static
JSObject* MozjsDOMStringTestInterface::CreateProxy(
JSContext* context, const scoped_refptr<Wrappable>& wrappable) {
+ JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+ DCHECK(global_object);
+
InterfaceData* interface_data = GetInterfaceData(context);
- JS::RootedObject prototype(context, GetPrototype(context));
+ JS::RootedObject prototype(context, GetPrototype(context, global_object));
DCHECK(prototype);
JS::RootedObject new_object(context, JS_NewObjectWithGivenProto(
context, &interface_data->instance_class_definition, prototype, NULL));
@@ -538,34 +560,45 @@
JS::RootedObject proxy(context,
ProxyHandler::NewProxy(context, new_object, prototype, NULL,
proxy_handler.Pointer()));
- WrapperPrivate::AddPrivateData(proxy, wrappable);
+ WrapperPrivate::AddPrivateData(context, proxy, wrappable);
return proxy;
}
//static
const JSClass* MozjsDOMStringTestInterface::PrototypeClass(
JSContext* context) {
- JS::RootedObject prototype(context, GetPrototype(context));
+ JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+ DCHECK(global_object);
+
+ JS::RootedObject prototype(context, GetPrototype(context, global_object));
JSClass* proto_class = JS_GetClass(*prototype.address());
return proto_class;
}
// static
-JSObject* MozjsDOMStringTestInterface::GetPrototype(JSContext* context) {
+JSObject* MozjsDOMStringTestInterface::GetPrototype(
+ JSContext* context, JS::HandleObject global_object) {
+ DCHECK(JS_IsGlobalObject(global_object));
+
InterfaceData* interface_data = GetInterfaceData(context);
if (!interface_data->prototype) {
// Create new prototype that has all the props and methods
- InitializePrototypeAndInterfaceObject(interface_data, context);
+ InitializePrototypeAndInterfaceObject(
+ interface_data, context, global_object);
}
DCHECK(interface_data->prototype);
return interface_data->prototype;
}
// static
-JSObject* MozjsDOMStringTestInterface::GetInterfaceObject(JSContext* context) {
+JSObject* MozjsDOMStringTestInterface::GetInterfaceObject(
+ JSContext* context, JS::HandleObject global_object) {
+ DCHECK(JS_IsGlobalObject(global_object));
+
InterfaceData* interface_data = GetInterfaceData(context);
if (!interface_data->interface_object) {
- InitializePrototypeAndInterfaceObject(interface_data, context);
+ InitializePrototypeAndInterfaceObject(
+ interface_data, context, global_object);
}
DCHECK(interface_data->interface_object);
return interface_data->interface_object;
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsDOMStringTestInterface.h b/src/cobalt/bindings/generated/mozjs/testing/MozjsDOMStringTestInterface.h
index 0cde0d8..875490c 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsDOMStringTestInterface.h
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsDOMStringTestInterface.h
@@ -41,8 +41,10 @@
static JSObject* CreateProxy(JSContext* context,
const scoped_refptr<script::Wrappable>& wrappable);
static const JSClass* PrototypeClass(JSContext* context);
- static JSObject* GetPrototype(JSContext* context);
- static JSObject* GetInterfaceObject(JSContext* context);
+ static JSObject* GetPrototype(JSContext* context,
+ JS::HandleObject global_object);
+ static JSObject* GetInterfaceObject(JSContext* context,
+ JS::HandleObject global_object);
};
} // namespace bindings
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsDerivedGetterSetterInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsDerivedGetterSetterInterface.cc
index 7770e5c..e84fa83 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsDerivedGetterSetterInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsDerivedGetterSetterInterface.cc
@@ -296,6 +296,26 @@
static base::LazyInstance<MozjsDerivedGetterSetterInterfaceHandler>
proxy_handler;
+JSBool HasInstance(JSContext *context, JS::HandleObject type,
+ JS::MutableHandleValue vp, JSBool *success) {
+ JS::RootedObject global_object(
+ context, JS_GetGlobalForObject(context, type));
+ DCHECK(global_object);
+
+ JS::RootedObject prototype(
+ context, MozjsDerivedGetterSetterInterface::GetPrototype(context, global_object));
+
+ // |IsDelegate| walks the prototype chain of an object returning true if
+ // .prototype is found.
+ bool is_delegate;
+ if (!IsDelegate(context, prototype, vp, &is_delegate)) {
+ *success = false;
+ return false;
+ }
+
+ *success = is_delegate;
+ return true;
+}
InterfaceData* CreateCachedInterfaceData() {
InterfaceData* interface_data = new InterfaceData();
@@ -344,6 +364,7 @@
interface_object_class->enumerate = JS_EnumerateStub;
interface_object_class->resolve = JS_ResolveStub;
interface_object_class->convert = JS_ConvertStub;
+ interface_object_class->hasInstance = &HasInstance;
return interface_data;
}
@@ -608,16 +629,14 @@
};
void InitializePrototypeAndInterfaceObject(
- InterfaceData* interface_data, JSContext* context) {
+ InterfaceData* interface_data, JSContext* context,
+ JS::HandleObject global_object) {
DCHECK(!interface_data->prototype);
DCHECK(!interface_data->interface_object);
+ DCHECK(JS_IsGlobalObject(global_object));
- MozjsGlobalObjectProxy* global_object_proxy =
- static_cast<MozjsGlobalObjectProxy*>(JS_GetContextPrivate(context));
- JS::RootedObject global_object(context, global_object_proxy->global_object());
- DCHECK(global_object);
JS::RootedObject parent_prototype(
- context, bindings::testing::MozjsNamedIndexedGetterInterface::GetPrototype(context));
+ context, bindings::testing::MozjsNamedIndexedGetterInterface::GetPrototype(context, global_object));
DCHECK(parent_prototype);
// Create the Prototype object.
@@ -694,8 +713,11 @@
// static
JSObject* MozjsDerivedGetterSetterInterface::CreateProxy(
JSContext* context, const scoped_refptr<Wrappable>& wrappable) {
+ JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+ DCHECK(global_object);
+
InterfaceData* interface_data = GetInterfaceData(context);
- JS::RootedObject prototype(context, GetPrototype(context));
+ JS::RootedObject prototype(context, GetPrototype(context, global_object));
DCHECK(prototype);
JS::RootedObject new_object(context, JS_NewObjectWithGivenProto(
context, &interface_data->instance_class_definition, prototype, NULL));
@@ -703,34 +725,45 @@
JS::RootedObject proxy(context,
ProxyHandler::NewProxy(context, new_object, prototype, NULL,
proxy_handler.Pointer()));
- WrapperPrivate::AddPrivateData(proxy, wrappable);
+ WrapperPrivate::AddPrivateData(context, proxy, wrappable);
return proxy;
}
//static
const JSClass* MozjsDerivedGetterSetterInterface::PrototypeClass(
JSContext* context) {
- JS::RootedObject prototype(context, GetPrototype(context));
+ JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+ DCHECK(global_object);
+
+ JS::RootedObject prototype(context, GetPrototype(context, global_object));
JSClass* proto_class = JS_GetClass(*prototype.address());
return proto_class;
}
// static
-JSObject* MozjsDerivedGetterSetterInterface::GetPrototype(JSContext* context) {
+JSObject* MozjsDerivedGetterSetterInterface::GetPrototype(
+ JSContext* context, JS::HandleObject global_object) {
+ DCHECK(JS_IsGlobalObject(global_object));
+
InterfaceData* interface_data = GetInterfaceData(context);
if (!interface_data->prototype) {
// Create new prototype that has all the props and methods
- InitializePrototypeAndInterfaceObject(interface_data, context);
+ InitializePrototypeAndInterfaceObject(
+ interface_data, context, global_object);
}
DCHECK(interface_data->prototype);
return interface_data->prototype;
}
// static
-JSObject* MozjsDerivedGetterSetterInterface::GetInterfaceObject(JSContext* context) {
+JSObject* MozjsDerivedGetterSetterInterface::GetInterfaceObject(
+ JSContext* context, JS::HandleObject global_object) {
+ DCHECK(JS_IsGlobalObject(global_object));
+
InterfaceData* interface_data = GetInterfaceData(context);
if (!interface_data->interface_object) {
- InitializePrototypeAndInterfaceObject(interface_data, context);
+ InitializePrototypeAndInterfaceObject(
+ interface_data, context, global_object);
}
DCHECK(interface_data->interface_object);
return interface_data->interface_object;
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsDerivedGetterSetterInterface.h b/src/cobalt/bindings/generated/mozjs/testing/MozjsDerivedGetterSetterInterface.h
index 6913c19..b0164cab 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsDerivedGetterSetterInterface.h
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsDerivedGetterSetterInterface.h
@@ -42,8 +42,10 @@
static JSObject* CreateProxy(JSContext* context,
const scoped_refptr<script::Wrappable>& wrappable);
static const JSClass* PrototypeClass(JSContext* context);
- static JSObject* GetPrototype(JSContext* context);
- static JSObject* GetInterfaceObject(JSContext* context);
+ static JSObject* GetPrototype(JSContext* context,
+ JS::HandleObject global_object);
+ static JSObject* GetInterfaceObject(JSContext* context,
+ JS::HandleObject global_object);
};
} // namespace bindings
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsDerivedInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsDerivedInterface.cc
index 96a27ce..3edab69 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsDerivedInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsDerivedInterface.cc
@@ -115,6 +115,26 @@
proxy_handler;
JSBool Constructor(JSContext* context, unsigned int argc, JS::Value* vp);
+JSBool HasInstance(JSContext *context, JS::HandleObject type,
+ JS::MutableHandleValue vp, JSBool *success) {
+ JS::RootedObject global_object(
+ context, JS_GetGlobalForObject(context, type));
+ DCHECK(global_object);
+
+ JS::RootedObject prototype(
+ context, MozjsDerivedInterface::GetPrototype(context, global_object));
+
+ // |IsDelegate| walks the prototype chain of an object returning true if
+ // .prototype is found.
+ bool is_delegate;
+ if (!IsDelegate(context, prototype, vp, &is_delegate)) {
+ *success = false;
+ return false;
+ }
+
+ *success = is_delegate;
+ return true;
+}
InterfaceData* CreateCachedInterfaceData() {
InterfaceData* interface_data = new InterfaceData();
@@ -163,6 +183,7 @@
interface_object_class->enumerate = JS_EnumerateStub;
interface_object_class->resolve = JS_ResolveStub;
interface_object_class->convert = JS_ConvertStub;
+ interface_object_class->hasInstance = &HasInstance;
interface_object_class->construct = Constructor;
return interface_data;
}
@@ -252,16 +273,14 @@
};
void InitializePrototypeAndInterfaceObject(
- InterfaceData* interface_data, JSContext* context) {
+ InterfaceData* interface_data, JSContext* context,
+ JS::HandleObject global_object) {
DCHECK(!interface_data->prototype);
DCHECK(!interface_data->interface_object);
+ DCHECK(JS_IsGlobalObject(global_object));
- MozjsGlobalObjectProxy* global_object_proxy =
- static_cast<MozjsGlobalObjectProxy*>(JS_GetContextPrivate(context));
- JS::RootedObject global_object(context, global_object_proxy->global_object());
- DCHECK(global_object);
JS::RootedObject parent_prototype(
- context, bindings::testing::MozjsBaseInterface::GetPrototype(context));
+ context, bindings::testing::MozjsBaseInterface::GetPrototype(context, global_object));
DCHECK(parent_prototype);
// Create the Prototype object.
@@ -348,8 +367,11 @@
// static
JSObject* MozjsDerivedInterface::CreateProxy(
JSContext* context, const scoped_refptr<Wrappable>& wrappable) {
+ JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+ DCHECK(global_object);
+
InterfaceData* interface_data = GetInterfaceData(context);
- JS::RootedObject prototype(context, GetPrototype(context));
+ JS::RootedObject prototype(context, GetPrototype(context, global_object));
DCHECK(prototype);
JS::RootedObject new_object(context, JS_NewObjectWithGivenProto(
context, &interface_data->instance_class_definition, prototype, NULL));
@@ -357,34 +379,45 @@
JS::RootedObject proxy(context,
ProxyHandler::NewProxy(context, new_object, prototype, NULL,
proxy_handler.Pointer()));
- WrapperPrivate::AddPrivateData(proxy, wrappable);
+ WrapperPrivate::AddPrivateData(context, proxy, wrappable);
return proxy;
}
//static
const JSClass* MozjsDerivedInterface::PrototypeClass(
JSContext* context) {
- JS::RootedObject prototype(context, GetPrototype(context));
+ JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+ DCHECK(global_object);
+
+ JS::RootedObject prototype(context, GetPrototype(context, global_object));
JSClass* proto_class = JS_GetClass(*prototype.address());
return proto_class;
}
// static
-JSObject* MozjsDerivedInterface::GetPrototype(JSContext* context) {
+JSObject* MozjsDerivedInterface::GetPrototype(
+ JSContext* context, JS::HandleObject global_object) {
+ DCHECK(JS_IsGlobalObject(global_object));
+
InterfaceData* interface_data = GetInterfaceData(context);
if (!interface_data->prototype) {
// Create new prototype that has all the props and methods
- InitializePrototypeAndInterfaceObject(interface_data, context);
+ InitializePrototypeAndInterfaceObject(
+ interface_data, context, global_object);
}
DCHECK(interface_data->prototype);
return interface_data->prototype;
}
// static
-JSObject* MozjsDerivedInterface::GetInterfaceObject(JSContext* context) {
+JSObject* MozjsDerivedInterface::GetInterfaceObject(
+ JSContext* context, JS::HandleObject global_object) {
+ DCHECK(JS_IsGlobalObject(global_object));
+
InterfaceData* interface_data = GetInterfaceData(context);
if (!interface_data->interface_object) {
- InitializePrototypeAndInterfaceObject(interface_data, context);
+ InitializePrototypeAndInterfaceObject(
+ interface_data, context, global_object);
}
DCHECK(interface_data->interface_object);
return interface_data->interface_object;
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsDerivedInterface.h b/src/cobalt/bindings/generated/mozjs/testing/MozjsDerivedInterface.h
index 59beb06..ac9780c 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsDerivedInterface.h
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsDerivedInterface.h
@@ -42,8 +42,10 @@
static JSObject* CreateProxy(JSContext* context,
const scoped_refptr<script::Wrappable>& wrappable);
static const JSClass* PrototypeClass(JSContext* context);
- static JSObject* GetPrototype(JSContext* context);
- static JSObject* GetInterfaceObject(JSContext* context);
+ static JSObject* GetPrototype(JSContext* context,
+ JS::HandleObject global_object);
+ static JSObject* GetInterfaceObject(JSContext* context,
+ JS::HandleObject global_object);
};
} // namespace bindings
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsDisabledInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsDisabledInterface.cc
index baf4573..54c8308 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsDisabledInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsDisabledInterface.cc
@@ -116,6 +116,26 @@
static base::LazyInstance<MozjsDisabledInterfaceHandler>
proxy_handler;
+JSBool HasInstance(JSContext *context, JS::HandleObject type,
+ JS::MutableHandleValue vp, JSBool *success) {
+ JS::RootedObject global_object(
+ context, JS_GetGlobalForObject(context, type));
+ DCHECK(global_object);
+
+ JS::RootedObject prototype(
+ context, MozjsDisabledInterface::GetPrototype(context, global_object));
+
+ // |IsDelegate| walks the prototype chain of an object returning true if
+ // .prototype is found.
+ bool is_delegate;
+ if (!IsDelegate(context, prototype, vp, &is_delegate)) {
+ *success = false;
+ return false;
+ }
+
+ *success = is_delegate;
+ return true;
+}
InterfaceData* CreateCachedInterfaceData() {
InterfaceData* interface_data = new InterfaceData();
@@ -164,6 +184,7 @@
interface_object_class->enumerate = JS_EnumerateStub;
interface_object_class->resolve = JS_ResolveStub;
interface_object_class->convert = JS_ConvertStub;
+ interface_object_class->hasInstance = &HasInstance;
return interface_data;
}
@@ -274,14 +295,12 @@
};
void InitializePrototypeAndInterfaceObject(
- InterfaceData* interface_data, JSContext* context) {
+ InterfaceData* interface_data, JSContext* context,
+ JS::HandleObject global_object) {
DCHECK(!interface_data->prototype);
DCHECK(!interface_data->interface_object);
+ DCHECK(JS_IsGlobalObject(global_object));
- MozjsGlobalObjectProxy* global_object_proxy =
- static_cast<MozjsGlobalObjectProxy*>(JS_GetContextPrivate(context));
- JS::RootedObject global_object(context, global_object_proxy->global_object());
- DCHECK(global_object);
JS::RootedObject parent_prototype(
context, JS_GetObjectPrototype(context, global_object));
DCHECK(parent_prototype);
@@ -360,8 +379,11 @@
// static
JSObject* MozjsDisabledInterface::CreateProxy(
JSContext* context, const scoped_refptr<Wrappable>& wrappable) {
+ JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+ DCHECK(global_object);
+
InterfaceData* interface_data = GetInterfaceData(context);
- JS::RootedObject prototype(context, GetPrototype(context));
+ JS::RootedObject prototype(context, GetPrototype(context, global_object));
DCHECK(prototype);
JS::RootedObject new_object(context, JS_NewObjectWithGivenProto(
context, &interface_data->instance_class_definition, prototype, NULL));
@@ -369,34 +391,45 @@
JS::RootedObject proxy(context,
ProxyHandler::NewProxy(context, new_object, prototype, NULL,
proxy_handler.Pointer()));
- WrapperPrivate::AddPrivateData(proxy, wrappable);
+ WrapperPrivate::AddPrivateData(context, proxy, wrappable);
return proxy;
}
//static
const JSClass* MozjsDisabledInterface::PrototypeClass(
JSContext* context) {
- JS::RootedObject prototype(context, GetPrototype(context));
+ JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+ DCHECK(global_object);
+
+ JS::RootedObject prototype(context, GetPrototype(context, global_object));
JSClass* proto_class = JS_GetClass(*prototype.address());
return proto_class;
}
// static
-JSObject* MozjsDisabledInterface::GetPrototype(JSContext* context) {
+JSObject* MozjsDisabledInterface::GetPrototype(
+ JSContext* context, JS::HandleObject global_object) {
+ DCHECK(JS_IsGlobalObject(global_object));
+
InterfaceData* interface_data = GetInterfaceData(context);
if (!interface_data->prototype) {
// Create new prototype that has all the props and methods
- InitializePrototypeAndInterfaceObject(interface_data, context);
+ InitializePrototypeAndInterfaceObject(
+ interface_data, context, global_object);
}
DCHECK(interface_data->prototype);
return interface_data->prototype;
}
// static
-JSObject* MozjsDisabledInterface::GetInterfaceObject(JSContext* context) {
+JSObject* MozjsDisabledInterface::GetInterfaceObject(
+ JSContext* context, JS::HandleObject global_object) {
+ DCHECK(JS_IsGlobalObject(global_object));
+
InterfaceData* interface_data = GetInterfaceData(context);
if (!interface_data->interface_object) {
- InitializePrototypeAndInterfaceObject(interface_data, context);
+ InitializePrototypeAndInterfaceObject(
+ interface_data, context, global_object);
}
DCHECK(interface_data->interface_object);
return interface_data->interface_object;
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsDisabledInterface.h b/src/cobalt/bindings/generated/mozjs/testing/MozjsDisabledInterface.h
index 360c946..bbef7b3 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsDisabledInterface.h
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsDisabledInterface.h
@@ -43,8 +43,10 @@
static JSObject* CreateProxy(JSContext* context,
const scoped_refptr<script::Wrappable>& wrappable);
static const JSClass* PrototypeClass(JSContext* context);
- static JSObject* GetPrototype(JSContext* context);
- static JSObject* GetInterfaceObject(JSContext* context);
+ static JSObject* GetPrototype(JSContext* context,
+ JS::HandleObject global_object);
+ static JSObject* GetInterfaceObject(JSContext* context,
+ JS::HandleObject global_object);
};
} // namespace bindings
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsEnumerationInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsEnumerationInterface.cc
index 2ed75aa..1ec0bac 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsEnumerationInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsEnumerationInterface.cc
@@ -124,6 +124,26 @@
proxy_handler;
JSBool Constructor(JSContext* context, unsigned int argc, JS::Value* vp);
+JSBool HasInstance(JSContext *context, JS::HandleObject type,
+ JS::MutableHandleValue vp, JSBool *success) {
+ JS::RootedObject global_object(
+ context, JS_GetGlobalForObject(context, type));
+ DCHECK(global_object);
+
+ JS::RootedObject prototype(
+ context, MozjsEnumerationInterface::GetPrototype(context, global_object));
+
+ // |IsDelegate| walks the prototype chain of an object returning true if
+ // .prototype is found.
+ bool is_delegate;
+ if (!IsDelegate(context, prototype, vp, &is_delegate)) {
+ *success = false;
+ return false;
+ }
+
+ *success = is_delegate;
+ return true;
+}
InterfaceData* CreateCachedInterfaceData() {
InterfaceData* interface_data = new InterfaceData();
@@ -172,6 +192,7 @@
interface_object_class->enumerate = JS_EnumerateStub;
interface_object_class->resolve = JS_ResolveStub;
interface_object_class->convert = JS_ConvertStub;
+ interface_object_class->hasInstance = &HasInstance;
interface_object_class->construct = Constructor;
return interface_data;
}
@@ -248,14 +269,12 @@
};
void InitializePrototypeAndInterfaceObject(
- InterfaceData* interface_data, JSContext* context) {
+ InterfaceData* interface_data, JSContext* context,
+ JS::HandleObject global_object) {
DCHECK(!interface_data->prototype);
DCHECK(!interface_data->interface_object);
+ DCHECK(JS_IsGlobalObject(global_object));
- MozjsGlobalObjectProxy* global_object_proxy =
- static_cast<MozjsGlobalObjectProxy*>(JS_GetContextPrivate(context));
- JS::RootedObject global_object(context, global_object_proxy->global_object());
- DCHECK(global_object);
JS::RootedObject parent_prototype(
context, JS_GetObjectPrototype(context, global_object));
DCHECK(parent_prototype);
@@ -344,8 +363,11 @@
// static
JSObject* MozjsEnumerationInterface::CreateProxy(
JSContext* context, const scoped_refptr<Wrappable>& wrappable) {
+ JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+ DCHECK(global_object);
+
InterfaceData* interface_data = GetInterfaceData(context);
- JS::RootedObject prototype(context, GetPrototype(context));
+ JS::RootedObject prototype(context, GetPrototype(context, global_object));
DCHECK(prototype);
JS::RootedObject new_object(context, JS_NewObjectWithGivenProto(
context, &interface_data->instance_class_definition, prototype, NULL));
@@ -353,34 +375,45 @@
JS::RootedObject proxy(context,
ProxyHandler::NewProxy(context, new_object, prototype, NULL,
proxy_handler.Pointer()));
- WrapperPrivate::AddPrivateData(proxy, wrappable);
+ WrapperPrivate::AddPrivateData(context, proxy, wrappable);
return proxy;
}
//static
const JSClass* MozjsEnumerationInterface::PrototypeClass(
JSContext* context) {
- JS::RootedObject prototype(context, GetPrototype(context));
+ JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+ DCHECK(global_object);
+
+ JS::RootedObject prototype(context, GetPrototype(context, global_object));
JSClass* proto_class = JS_GetClass(*prototype.address());
return proto_class;
}
// static
-JSObject* MozjsEnumerationInterface::GetPrototype(JSContext* context) {
+JSObject* MozjsEnumerationInterface::GetPrototype(
+ JSContext* context, JS::HandleObject global_object) {
+ DCHECK(JS_IsGlobalObject(global_object));
+
InterfaceData* interface_data = GetInterfaceData(context);
if (!interface_data->prototype) {
// Create new prototype that has all the props and methods
- InitializePrototypeAndInterfaceObject(interface_data, context);
+ InitializePrototypeAndInterfaceObject(
+ interface_data, context, global_object);
}
DCHECK(interface_data->prototype);
return interface_data->prototype;
}
// static
-JSObject* MozjsEnumerationInterface::GetInterfaceObject(JSContext* context) {
+JSObject* MozjsEnumerationInterface::GetInterfaceObject(
+ JSContext* context, JS::HandleObject global_object) {
+ DCHECK(JS_IsGlobalObject(global_object));
+
InterfaceData* interface_data = GetInterfaceData(context);
if (!interface_data->interface_object) {
- InitializePrototypeAndInterfaceObject(interface_data, context);
+ InitializePrototypeAndInterfaceObject(
+ interface_data, context, global_object);
}
DCHECK(interface_data->interface_object);
return interface_data->interface_object;
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsEnumerationInterface.h b/src/cobalt/bindings/generated/mozjs/testing/MozjsEnumerationInterface.h
index b4b3e19..34f404e 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsEnumerationInterface.h
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsEnumerationInterface.h
@@ -41,8 +41,10 @@
static JSObject* CreateProxy(JSContext* context,
const scoped_refptr<script::Wrappable>& wrappable);
static const JSClass* PrototypeClass(JSContext* context);
- static JSObject* GetPrototype(JSContext* context);
- static JSObject* GetInterfaceObject(JSContext* context);
+ static JSObject* GetPrototype(JSContext* context,
+ JS::HandleObject global_object);
+ static JSObject* GetInterfaceObject(JSContext* context,
+ JS::HandleObject global_object);
};
} // namespace bindings
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsExceptionObjectInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsExceptionObjectInterface.cc
index 498e223..8a5b4b0 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsExceptionObjectInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsExceptionObjectInterface.cc
@@ -43,6 +43,7 @@
#include "cobalt/script/mozjs/wrapper_private.h"
#include "cobalt/script/property_enumerator.h"
#include "third_party/mozjs/js/src/jsapi.h"
+#include "third_party/mozjs/js/src/jsexn.h"
#include "third_party/mozjs/js/src/jsfriendapi.h"
namespace {
@@ -114,6 +115,26 @@
static base::LazyInstance<MozjsExceptionObjectInterfaceHandler>
proxy_handler;
+JSBool HasInstance(JSContext *context, JS::HandleObject type,
+ JS::MutableHandleValue vp, JSBool *success) {
+ JS::RootedObject global_object(
+ context, JS_GetGlobalForObject(context, type));
+ DCHECK(global_object);
+
+ JS::RootedObject prototype(
+ context, MozjsExceptionObjectInterface::GetPrototype(context, global_object));
+
+ // |IsDelegate| walks the prototype chain of an object returning true if
+ // .prototype is found.
+ bool is_delegate;
+ if (!IsDelegate(context, prototype, vp, &is_delegate)) {
+ *success = false;
+ return false;
+ }
+
+ *success = is_delegate;
+ return true;
+}
InterfaceData* CreateCachedInterfaceData() {
InterfaceData* interface_data = new InterfaceData();
@@ -162,6 +183,7 @@
interface_object_class->enumerate = JS_EnumerateStub;
interface_object_class->resolve = JS_ResolveStub;
interface_object_class->convert = JS_ConvertStub;
+ interface_object_class->hasInstance = &HasInstance;
return interface_data;
}
@@ -243,22 +265,22 @@
};
void InitializePrototypeAndInterfaceObject(
- InterfaceData* interface_data, JSContext* context) {
+ InterfaceData* interface_data, JSContext* context,
+ JS::HandleObject global_object) {
DCHECK(!interface_data->prototype);
DCHECK(!interface_data->interface_object);
+ DCHECK(JS_IsGlobalObject(global_object));
- MozjsGlobalObjectProxy* global_object_proxy =
- static_cast<MozjsGlobalObjectProxy*>(JS_GetContextPrivate(context));
- JS::RootedObject global_object(context, global_object_proxy->global_object());
- DCHECK(global_object);
JS::RootedObject parent_prototype(
context, JS_GetObjectPrototype(context, global_object));
DCHECK(parent_prototype);
- // Create the Prototype object.
- interface_data->prototype = JS_NewObjectWithGivenProto(
- context, &interface_data->prototype_class_definition, parent_prototype,
- NULL);
+ JS::RootedObject prototype(context);
+ // Get Error prototype.
+ bool success_check = js_GetClassPrototype(
+ context, GetExceptionProtoKey(JSEXN_ERR), &prototype);
+ DCHECK(success_check);
+ interface_data->prototype = prototype;
bool success = JS_DefineProperties(
context, interface_data->prototype, prototype_properties);
DCHECK(success);
@@ -329,8 +351,11 @@
// static
JSObject* MozjsExceptionObjectInterface::CreateProxy(
JSContext* context, const scoped_refptr<Wrappable>& wrappable) {
+ JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+ DCHECK(global_object);
+
InterfaceData* interface_data = GetInterfaceData(context);
- JS::RootedObject prototype(context, GetPrototype(context));
+ JS::RootedObject prototype(context, GetPrototype(context, global_object));
DCHECK(prototype);
JS::RootedObject new_object(context, JS_NewObjectWithGivenProto(
context, &interface_data->instance_class_definition, prototype, NULL));
@@ -338,34 +363,45 @@
JS::RootedObject proxy(context,
ProxyHandler::NewProxy(context, new_object, prototype, NULL,
proxy_handler.Pointer()));
- WrapperPrivate::AddPrivateData(proxy, wrappable);
+ WrapperPrivate::AddPrivateData(context, proxy, wrappable);
return proxy;
}
//static
const JSClass* MozjsExceptionObjectInterface::PrototypeClass(
JSContext* context) {
- JS::RootedObject prototype(context, GetPrototype(context));
+ JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+ DCHECK(global_object);
+
+ JS::RootedObject prototype(context, GetPrototype(context, global_object));
JSClass* proto_class = JS_GetClass(*prototype.address());
return proto_class;
}
// static
-JSObject* MozjsExceptionObjectInterface::GetPrototype(JSContext* context) {
+JSObject* MozjsExceptionObjectInterface::GetPrototype(
+ JSContext* context, JS::HandleObject global_object) {
+ DCHECK(JS_IsGlobalObject(global_object));
+
InterfaceData* interface_data = GetInterfaceData(context);
if (!interface_data->prototype) {
// Create new prototype that has all the props and methods
- InitializePrototypeAndInterfaceObject(interface_data, context);
+ InitializePrototypeAndInterfaceObject(
+ interface_data, context, global_object);
}
DCHECK(interface_data->prototype);
return interface_data->prototype;
}
// static
-JSObject* MozjsExceptionObjectInterface::GetInterfaceObject(JSContext* context) {
+JSObject* MozjsExceptionObjectInterface::GetInterfaceObject(
+ JSContext* context, JS::HandleObject global_object) {
+ DCHECK(JS_IsGlobalObject(global_object));
+
InterfaceData* interface_data = GetInterfaceData(context);
if (!interface_data->interface_object) {
- InitializePrototypeAndInterfaceObject(interface_data, context);
+ InitializePrototypeAndInterfaceObject(
+ interface_data, context, global_object);
}
DCHECK(interface_data->interface_object);
return interface_data->interface_object;
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsExceptionObjectInterface.h b/src/cobalt/bindings/generated/mozjs/testing/MozjsExceptionObjectInterface.h
index 0ba0055..4c8282d 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsExceptionObjectInterface.h
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsExceptionObjectInterface.h
@@ -41,8 +41,10 @@
static JSObject* CreateProxy(JSContext* context,
const scoped_refptr<script::Wrappable>& wrappable);
static const JSClass* PrototypeClass(JSContext* context);
- static JSObject* GetPrototype(JSContext* context);
- static JSObject* GetInterfaceObject(JSContext* context);
+ static JSObject* GetPrototype(JSContext* context,
+ JS::HandleObject global_object);
+ static JSObject* GetInterfaceObject(JSContext* context,
+ JS::HandleObject global_object);
};
} // namespace bindings
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsExceptionsInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsExceptionsInterface.cc
index 21cbe31..c58594c 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsExceptionsInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsExceptionsInterface.cc
@@ -115,6 +115,26 @@
proxy_handler;
JSBool Constructor(JSContext* context, unsigned int argc, JS::Value* vp);
+JSBool HasInstance(JSContext *context, JS::HandleObject type,
+ JS::MutableHandleValue vp, JSBool *success) {
+ JS::RootedObject global_object(
+ context, JS_GetGlobalForObject(context, type));
+ DCHECK(global_object);
+
+ JS::RootedObject prototype(
+ context, MozjsExceptionsInterface::GetPrototype(context, global_object));
+
+ // |IsDelegate| walks the prototype chain of an object returning true if
+ // .prototype is found.
+ bool is_delegate;
+ if (!IsDelegate(context, prototype, vp, &is_delegate)) {
+ *success = false;
+ return false;
+ }
+
+ *success = is_delegate;
+ return true;
+}
InterfaceData* CreateCachedInterfaceData() {
InterfaceData* interface_data = new InterfaceData();
@@ -163,6 +183,7 @@
interface_object_class->enumerate = JS_EnumerateStub;
interface_object_class->resolve = JS_ResolveStub;
interface_object_class->convert = JS_ConvertStub;
+ interface_object_class->hasInstance = &HasInstance;
interface_object_class->construct = Constructor;
return interface_data;
}
@@ -274,14 +295,12 @@
};
void InitializePrototypeAndInterfaceObject(
- InterfaceData* interface_data, JSContext* context) {
+ InterfaceData* interface_data, JSContext* context,
+ JS::HandleObject global_object) {
DCHECK(!interface_data->prototype);
DCHECK(!interface_data->interface_object);
+ DCHECK(JS_IsGlobalObject(global_object));
- MozjsGlobalObjectProxy* global_object_proxy =
- static_cast<MozjsGlobalObjectProxy*>(JS_GetContextPrivate(context));
- JS::RootedObject global_object(context, global_object_proxy->global_object());
- DCHECK(global_object);
JS::RootedObject parent_prototype(
context, JS_GetObjectPrototype(context, global_object));
DCHECK(parent_prototype);
@@ -370,8 +389,11 @@
// static
JSObject* MozjsExceptionsInterface::CreateProxy(
JSContext* context, const scoped_refptr<Wrappable>& wrappable) {
+ JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+ DCHECK(global_object);
+
InterfaceData* interface_data = GetInterfaceData(context);
- JS::RootedObject prototype(context, GetPrototype(context));
+ JS::RootedObject prototype(context, GetPrototype(context, global_object));
DCHECK(prototype);
JS::RootedObject new_object(context, JS_NewObjectWithGivenProto(
context, &interface_data->instance_class_definition, prototype, NULL));
@@ -379,34 +401,45 @@
JS::RootedObject proxy(context,
ProxyHandler::NewProxy(context, new_object, prototype, NULL,
proxy_handler.Pointer()));
- WrapperPrivate::AddPrivateData(proxy, wrappable);
+ WrapperPrivate::AddPrivateData(context, proxy, wrappable);
return proxy;
}
//static
const JSClass* MozjsExceptionsInterface::PrototypeClass(
JSContext* context) {
- JS::RootedObject prototype(context, GetPrototype(context));
+ JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+ DCHECK(global_object);
+
+ JS::RootedObject prototype(context, GetPrototype(context, global_object));
JSClass* proto_class = JS_GetClass(*prototype.address());
return proto_class;
}
// static
-JSObject* MozjsExceptionsInterface::GetPrototype(JSContext* context) {
+JSObject* MozjsExceptionsInterface::GetPrototype(
+ JSContext* context, JS::HandleObject global_object) {
+ DCHECK(JS_IsGlobalObject(global_object));
+
InterfaceData* interface_data = GetInterfaceData(context);
if (!interface_data->prototype) {
// Create new prototype that has all the props and methods
- InitializePrototypeAndInterfaceObject(interface_data, context);
+ InitializePrototypeAndInterfaceObject(
+ interface_data, context, global_object);
}
DCHECK(interface_data->prototype);
return interface_data->prototype;
}
// static
-JSObject* MozjsExceptionsInterface::GetInterfaceObject(JSContext* context) {
+JSObject* MozjsExceptionsInterface::GetInterfaceObject(
+ JSContext* context, JS::HandleObject global_object) {
+ DCHECK(JS_IsGlobalObject(global_object));
+
InterfaceData* interface_data = GetInterfaceData(context);
if (!interface_data->interface_object) {
- InitializePrototypeAndInterfaceObject(interface_data, context);
+ InitializePrototypeAndInterfaceObject(
+ interface_data, context, global_object);
}
DCHECK(interface_data->interface_object);
return interface_data->interface_object;
@@ -420,6 +453,10 @@
scoped_refptr<ExceptionsInterface> new_object =
new ExceptionsInterface(&exception_state);
+ // In case that an exception is thrown from constructor.
+ if (exception_state.is_exception_set()) {
+ return false;
+ }
JS::RootedValue result_value(context);
ToJSValue(context, new_object, &result_value);
DCHECK(result_value.isObject());
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsExceptionsInterface.h b/src/cobalt/bindings/generated/mozjs/testing/MozjsExceptionsInterface.h
index b5fe100..fa0457d 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsExceptionsInterface.h
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsExceptionsInterface.h
@@ -41,8 +41,10 @@
static JSObject* CreateProxy(JSContext* context,
const scoped_refptr<script::Wrappable>& wrappable);
static const JSClass* PrototypeClass(JSContext* context);
- static JSObject* GetPrototype(JSContext* context);
- static JSObject* GetInterfaceObject(JSContext* context);
+ static JSObject* GetPrototype(JSContext* context,
+ JS::HandleObject global_object);
+ static JSObject* GetInterfaceObject(JSContext* context,
+ JS::HandleObject global_object);
};
} // namespace bindings
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsExtendedIDLAttributesInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsExtendedIDLAttributesInterface.cc
index 06bcf72..3753f38 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsExtendedIDLAttributesInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsExtendedIDLAttributesInterface.cc
@@ -114,6 +114,26 @@
static base::LazyInstance<MozjsExtendedIDLAttributesInterfaceHandler>
proxy_handler;
+JSBool HasInstance(JSContext *context, JS::HandleObject type,
+ JS::MutableHandleValue vp, JSBool *success) {
+ JS::RootedObject global_object(
+ context, JS_GetGlobalForObject(context, type));
+ DCHECK(global_object);
+
+ JS::RootedObject prototype(
+ context, MozjsExtendedIDLAttributesInterface::GetPrototype(context, global_object));
+
+ // |IsDelegate| walks the prototype chain of an object returning true if
+ // .prototype is found.
+ bool is_delegate;
+ if (!IsDelegate(context, prototype, vp, &is_delegate)) {
+ *success = false;
+ return false;
+ }
+
+ *success = is_delegate;
+ return true;
+}
InterfaceData* CreateCachedInterfaceData() {
InterfaceData* interface_data = new InterfaceData();
@@ -162,6 +182,7 @@
interface_object_class->enumerate = JS_EnumerateStub;
interface_object_class->resolve = JS_ResolveStub;
interface_object_class->convert = JS_ConvertStub;
+ interface_object_class->hasInstance = &HasInstance;
return interface_data;
}
@@ -224,14 +245,12 @@
};
void InitializePrototypeAndInterfaceObject(
- InterfaceData* interface_data, JSContext* context) {
+ InterfaceData* interface_data, JSContext* context,
+ JS::HandleObject global_object) {
DCHECK(!interface_data->prototype);
DCHECK(!interface_data->interface_object);
+ DCHECK(JS_IsGlobalObject(global_object));
- MozjsGlobalObjectProxy* global_object_proxy =
- static_cast<MozjsGlobalObjectProxy*>(JS_GetContextPrivate(context));
- JS::RootedObject global_object(context, global_object_proxy->global_object());
- DCHECK(global_object);
JS::RootedObject parent_prototype(
context, JS_GetObjectPrototype(context, global_object));
DCHECK(parent_prototype);
@@ -310,8 +329,11 @@
// static
JSObject* MozjsExtendedIDLAttributesInterface::CreateProxy(
JSContext* context, const scoped_refptr<Wrappable>& wrappable) {
+ JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+ DCHECK(global_object);
+
InterfaceData* interface_data = GetInterfaceData(context);
- JS::RootedObject prototype(context, GetPrototype(context));
+ JS::RootedObject prototype(context, GetPrototype(context, global_object));
DCHECK(prototype);
JS::RootedObject new_object(context, JS_NewObjectWithGivenProto(
context, &interface_data->instance_class_definition, prototype, NULL));
@@ -319,34 +341,45 @@
JS::RootedObject proxy(context,
ProxyHandler::NewProxy(context, new_object, prototype, NULL,
proxy_handler.Pointer()));
- WrapperPrivate::AddPrivateData(proxy, wrappable);
+ WrapperPrivate::AddPrivateData(context, proxy, wrappable);
return proxy;
}
//static
const JSClass* MozjsExtendedIDLAttributesInterface::PrototypeClass(
JSContext* context) {
- JS::RootedObject prototype(context, GetPrototype(context));
+ JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+ DCHECK(global_object);
+
+ JS::RootedObject prototype(context, GetPrototype(context, global_object));
JSClass* proto_class = JS_GetClass(*prototype.address());
return proto_class;
}
// static
-JSObject* MozjsExtendedIDLAttributesInterface::GetPrototype(JSContext* context) {
+JSObject* MozjsExtendedIDLAttributesInterface::GetPrototype(
+ JSContext* context, JS::HandleObject global_object) {
+ DCHECK(JS_IsGlobalObject(global_object));
+
InterfaceData* interface_data = GetInterfaceData(context);
if (!interface_data->prototype) {
// Create new prototype that has all the props and methods
- InitializePrototypeAndInterfaceObject(interface_data, context);
+ InitializePrototypeAndInterfaceObject(
+ interface_data, context, global_object);
}
DCHECK(interface_data->prototype);
return interface_data->prototype;
}
// static
-JSObject* MozjsExtendedIDLAttributesInterface::GetInterfaceObject(JSContext* context) {
+JSObject* MozjsExtendedIDLAttributesInterface::GetInterfaceObject(
+ JSContext* context, JS::HandleObject global_object) {
+ DCHECK(JS_IsGlobalObject(global_object));
+
InterfaceData* interface_data = GetInterfaceData(context);
if (!interface_data->interface_object) {
- InitializePrototypeAndInterfaceObject(interface_data, context);
+ InitializePrototypeAndInterfaceObject(
+ interface_data, context, global_object);
}
DCHECK(interface_data->interface_object);
return interface_data->interface_object;
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsExtendedIDLAttributesInterface.h b/src/cobalt/bindings/generated/mozjs/testing/MozjsExtendedIDLAttributesInterface.h
index 68909d5..b99f5b7 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsExtendedIDLAttributesInterface.h
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsExtendedIDLAttributesInterface.h
@@ -41,8 +41,10 @@
static JSObject* CreateProxy(JSContext* context,
const scoped_refptr<script::Wrappable>& wrappable);
static const JSClass* PrototypeClass(JSContext* context);
- static JSObject* GetPrototype(JSContext* context);
- static JSObject* GetInterfaceObject(JSContext* context);
+ static JSObject* GetPrototype(JSContext* context,
+ JS::HandleObject global_object);
+ static JSObject* GetInterfaceObject(JSContext* context,
+ JS::HandleObject global_object);
};
} // namespace bindings
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsGetOpaqueRootInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsGetOpaqueRootInterface.cc
index fbfc60a..1a71dae 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsGetOpaqueRootInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsGetOpaqueRootInterface.cc
@@ -115,6 +115,26 @@
proxy_handler;
JSBool Constructor(JSContext* context, unsigned int argc, JS::Value* vp);
+JSBool HasInstance(JSContext *context, JS::HandleObject type,
+ JS::MutableHandleValue vp, JSBool *success) {
+ JS::RootedObject global_object(
+ context, JS_GetGlobalForObject(context, type));
+ DCHECK(global_object);
+
+ JS::RootedObject prototype(
+ context, MozjsGetOpaqueRootInterface::GetPrototype(context, global_object));
+
+ // |IsDelegate| walks the prototype chain of an object returning true if
+ // .prototype is found.
+ bool is_delegate;
+ if (!IsDelegate(context, prototype, vp, &is_delegate)) {
+ *success = false;
+ return false;
+ }
+
+ *success = is_delegate;
+ return true;
+}
InterfaceData* CreateCachedInterfaceData() {
InterfaceData* interface_data = new InterfaceData();
@@ -163,6 +183,7 @@
interface_object_class->enumerate = JS_EnumerateStub;
interface_object_class->resolve = JS_ResolveStub;
interface_object_class->convert = JS_ConvertStub;
+ interface_object_class->hasInstance = &HasInstance;
interface_object_class->construct = Constructor;
return interface_data;
}
@@ -189,14 +210,12 @@
};
void InitializePrototypeAndInterfaceObject(
- InterfaceData* interface_data, JSContext* context) {
+ InterfaceData* interface_data, JSContext* context,
+ JS::HandleObject global_object) {
DCHECK(!interface_data->prototype);
DCHECK(!interface_data->interface_object);
+ DCHECK(JS_IsGlobalObject(global_object));
- MozjsGlobalObjectProxy* global_object_proxy =
- static_cast<MozjsGlobalObjectProxy*>(JS_GetContextPrivate(context));
- JS::RootedObject global_object(context, global_object_proxy->global_object());
- DCHECK(global_object);
JS::RootedObject parent_prototype(
context, JS_GetObjectPrototype(context, global_object));
DCHECK(parent_prototype);
@@ -285,8 +304,11 @@
// static
JSObject* MozjsGetOpaqueRootInterface::CreateProxy(
JSContext* context, const scoped_refptr<Wrappable>& wrappable) {
+ JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+ DCHECK(global_object);
+
InterfaceData* interface_data = GetInterfaceData(context);
- JS::RootedObject prototype(context, GetPrototype(context));
+ JS::RootedObject prototype(context, GetPrototype(context, global_object));
DCHECK(prototype);
JS::RootedObject new_object(context, JS_NewObjectWithGivenProto(
context, &interface_data->instance_class_definition, prototype, NULL));
@@ -294,34 +316,45 @@
JS::RootedObject proxy(context,
ProxyHandler::NewProxy(context, new_object, prototype, NULL,
proxy_handler.Pointer()));
- WrapperPrivate::AddPrivateData(proxy, wrappable);
+ WrapperPrivate::AddPrivateData(context, proxy, wrappable);
return proxy;
}
//static
const JSClass* MozjsGetOpaqueRootInterface::PrototypeClass(
JSContext* context) {
- JS::RootedObject prototype(context, GetPrototype(context));
+ JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+ DCHECK(global_object);
+
+ JS::RootedObject prototype(context, GetPrototype(context, global_object));
JSClass* proto_class = JS_GetClass(*prototype.address());
return proto_class;
}
// static
-JSObject* MozjsGetOpaqueRootInterface::GetPrototype(JSContext* context) {
+JSObject* MozjsGetOpaqueRootInterface::GetPrototype(
+ JSContext* context, JS::HandleObject global_object) {
+ DCHECK(JS_IsGlobalObject(global_object));
+
InterfaceData* interface_data = GetInterfaceData(context);
if (!interface_data->prototype) {
// Create new prototype that has all the props and methods
- InitializePrototypeAndInterfaceObject(interface_data, context);
+ InitializePrototypeAndInterfaceObject(
+ interface_data, context, global_object);
}
DCHECK(interface_data->prototype);
return interface_data->prototype;
}
// static
-JSObject* MozjsGetOpaqueRootInterface::GetInterfaceObject(JSContext* context) {
+JSObject* MozjsGetOpaqueRootInterface::GetInterfaceObject(
+ JSContext* context, JS::HandleObject global_object) {
+ DCHECK(JS_IsGlobalObject(global_object));
+
InterfaceData* interface_data = GetInterfaceData(context);
if (!interface_data->interface_object) {
- InitializePrototypeAndInterfaceObject(interface_data, context);
+ InitializePrototypeAndInterfaceObject(
+ interface_data, context, global_object);
}
DCHECK(interface_data->interface_object);
return interface_data->interface_object;
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsGetOpaqueRootInterface.h b/src/cobalt/bindings/generated/mozjs/testing/MozjsGetOpaqueRootInterface.h
index 343e465..cfc9474 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsGetOpaqueRootInterface.h
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsGetOpaqueRootInterface.h
@@ -41,8 +41,10 @@
static JSObject* CreateProxy(JSContext* context,
const scoped_refptr<script::Wrappable>& wrappable);
static const JSClass* PrototypeClass(JSContext* context);
- static JSObject* GetPrototype(JSContext* context);
- static JSObject* GetInterfaceObject(JSContext* context);
+ static JSObject* GetPrototype(JSContext* context,
+ JS::HandleObject global_object);
+ static JSObject* GetInterfaceObject(JSContext* context,
+ JS::HandleObject global_object);
};
} // namespace bindings
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsGlobalInterfaceParent.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsGlobalInterfaceParent.cc
index 27e94db..e02ee9c 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsGlobalInterfaceParent.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsGlobalInterfaceParent.cc
@@ -114,6 +114,26 @@
static base::LazyInstance<MozjsGlobalInterfaceParentHandler>
proxy_handler;
+JSBool HasInstance(JSContext *context, JS::HandleObject type,
+ JS::MutableHandleValue vp, JSBool *success) {
+ JS::RootedObject global_object(
+ context, JS_GetGlobalForObject(context, type));
+ DCHECK(global_object);
+
+ JS::RootedObject prototype(
+ context, MozjsGlobalInterfaceParent::GetPrototype(context, global_object));
+
+ // |IsDelegate| walks the prototype chain of an object returning true if
+ // .prototype is found.
+ bool is_delegate;
+ if (!IsDelegate(context, prototype, vp, &is_delegate)) {
+ *success = false;
+ return false;
+ }
+
+ *success = is_delegate;
+ return true;
+}
InterfaceData* CreateCachedInterfaceData() {
InterfaceData* interface_data = new InterfaceData();
@@ -162,6 +182,7 @@
interface_object_class->enumerate = JS_EnumerateStub;
interface_object_class->resolve = JS_ResolveStub;
interface_object_class->convert = JS_ConvertStub;
+ interface_object_class->hasInstance = &HasInstance;
return interface_data;
}
@@ -222,14 +243,12 @@
};
void InitializePrototypeAndInterfaceObject(
- InterfaceData* interface_data, JSContext* context) {
+ InterfaceData* interface_data, JSContext* context,
+ JS::HandleObject global_object) {
DCHECK(!interface_data->prototype);
DCHECK(!interface_data->interface_object);
+ DCHECK(JS_IsGlobalObject(global_object));
- MozjsGlobalObjectProxy* global_object_proxy =
- static_cast<MozjsGlobalObjectProxy*>(JS_GetContextPrivate(context));
- JS::RootedObject global_object(context, global_object_proxy->global_object());
- DCHECK(global_object);
JS::RootedObject parent_prototype(
context, JS_GetObjectPrototype(context, global_object));
DCHECK(parent_prototype);
@@ -308,8 +327,11 @@
// static
JSObject* MozjsGlobalInterfaceParent::CreateProxy(
JSContext* context, const scoped_refptr<Wrappable>& wrappable) {
+ JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+ DCHECK(global_object);
+
InterfaceData* interface_data = GetInterfaceData(context);
- JS::RootedObject prototype(context, GetPrototype(context));
+ JS::RootedObject prototype(context, GetPrototype(context, global_object));
DCHECK(prototype);
JS::RootedObject new_object(context, JS_NewObjectWithGivenProto(
context, &interface_data->instance_class_definition, prototype, NULL));
@@ -317,34 +339,45 @@
JS::RootedObject proxy(context,
ProxyHandler::NewProxy(context, new_object, prototype, NULL,
proxy_handler.Pointer()));
- WrapperPrivate::AddPrivateData(proxy, wrappable);
+ WrapperPrivate::AddPrivateData(context, proxy, wrappable);
return proxy;
}
//static
const JSClass* MozjsGlobalInterfaceParent::PrototypeClass(
JSContext* context) {
- JS::RootedObject prototype(context, GetPrototype(context));
+ JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+ DCHECK(global_object);
+
+ JS::RootedObject prototype(context, GetPrototype(context, global_object));
JSClass* proto_class = JS_GetClass(*prototype.address());
return proto_class;
}
// static
-JSObject* MozjsGlobalInterfaceParent::GetPrototype(JSContext* context) {
+JSObject* MozjsGlobalInterfaceParent::GetPrototype(
+ JSContext* context, JS::HandleObject global_object) {
+ DCHECK(JS_IsGlobalObject(global_object));
+
InterfaceData* interface_data = GetInterfaceData(context);
if (!interface_data->prototype) {
// Create new prototype that has all the props and methods
- InitializePrototypeAndInterfaceObject(interface_data, context);
+ InitializePrototypeAndInterfaceObject(
+ interface_data, context, global_object);
}
DCHECK(interface_data->prototype);
return interface_data->prototype;
}
// static
-JSObject* MozjsGlobalInterfaceParent::GetInterfaceObject(JSContext* context) {
+JSObject* MozjsGlobalInterfaceParent::GetInterfaceObject(
+ JSContext* context, JS::HandleObject global_object) {
+ DCHECK(JS_IsGlobalObject(global_object));
+
InterfaceData* interface_data = GetInterfaceData(context);
if (!interface_data->interface_object) {
- InitializePrototypeAndInterfaceObject(interface_data, context);
+ InitializePrototypeAndInterfaceObject(
+ interface_data, context, global_object);
}
DCHECK(interface_data->interface_object);
return interface_data->interface_object;
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsGlobalInterfaceParent.h b/src/cobalt/bindings/generated/mozjs/testing/MozjsGlobalInterfaceParent.h
index 0ed43cb..2747058 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsGlobalInterfaceParent.h
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsGlobalInterfaceParent.h
@@ -41,8 +41,10 @@
static JSObject* CreateProxy(JSContext* context,
const scoped_refptr<script::Wrappable>& wrappable);
static const JSClass* PrototypeClass(JSContext* context);
- static JSObject* GetPrototype(JSContext* context);
- static JSObject* GetInterfaceObject(JSContext* context);
+ static JSObject* GetPrototype(JSContext* context,
+ JS::HandleObject global_object);
+ static JSObject* GetInterfaceObject(JSContext* context,
+ JS::HandleObject global_object);
};
} // namespace bindings
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsIndexedGetterInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsIndexedGetterInterface.cc
index e67543f..a392376 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsIndexedGetterInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsIndexedGetterInterface.cc
@@ -220,6 +220,26 @@
static base::LazyInstance<MozjsIndexedGetterInterfaceHandler>
proxy_handler;
+JSBool HasInstance(JSContext *context, JS::HandleObject type,
+ JS::MutableHandleValue vp, JSBool *success) {
+ JS::RootedObject global_object(
+ context, JS_GetGlobalForObject(context, type));
+ DCHECK(global_object);
+
+ JS::RootedObject prototype(
+ context, MozjsIndexedGetterInterface::GetPrototype(context, global_object));
+
+ // |IsDelegate| walks the prototype chain of an object returning true if
+ // .prototype is found.
+ bool is_delegate;
+ if (!IsDelegate(context, prototype, vp, &is_delegate)) {
+ *success = false;
+ return false;
+ }
+
+ *success = is_delegate;
+ return true;
+}
InterfaceData* CreateCachedInterfaceData() {
InterfaceData* interface_data = new InterfaceData();
@@ -268,6 +288,7 @@
interface_object_class->enumerate = JS_EnumerateStub;
interface_object_class->resolve = JS_ResolveStub;
interface_object_class->convert = JS_ConvertStub;
+ interface_object_class->hasInstance = &HasInstance;
return interface_data;
}
@@ -501,14 +522,12 @@
};
void InitializePrototypeAndInterfaceObject(
- InterfaceData* interface_data, JSContext* context) {
+ InterfaceData* interface_data, JSContext* context,
+ JS::HandleObject global_object) {
DCHECK(!interface_data->prototype);
DCHECK(!interface_data->interface_object);
+ DCHECK(JS_IsGlobalObject(global_object));
- MozjsGlobalObjectProxy* global_object_proxy =
- static_cast<MozjsGlobalObjectProxy*>(JS_GetContextPrivate(context));
- JS::RootedObject global_object(context, global_object_proxy->global_object());
- DCHECK(global_object);
JS::RootedObject parent_prototype(
context, JS_GetObjectPrototype(context, global_object));
DCHECK(parent_prototype);
@@ -587,8 +606,11 @@
// static
JSObject* MozjsIndexedGetterInterface::CreateProxy(
JSContext* context, const scoped_refptr<Wrappable>& wrappable) {
+ JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+ DCHECK(global_object);
+
InterfaceData* interface_data = GetInterfaceData(context);
- JS::RootedObject prototype(context, GetPrototype(context));
+ JS::RootedObject prototype(context, GetPrototype(context, global_object));
DCHECK(prototype);
JS::RootedObject new_object(context, JS_NewObjectWithGivenProto(
context, &interface_data->instance_class_definition, prototype, NULL));
@@ -596,34 +618,45 @@
JS::RootedObject proxy(context,
ProxyHandler::NewProxy(context, new_object, prototype, NULL,
proxy_handler.Pointer()));
- WrapperPrivate::AddPrivateData(proxy, wrappable);
+ WrapperPrivate::AddPrivateData(context, proxy, wrappable);
return proxy;
}
//static
const JSClass* MozjsIndexedGetterInterface::PrototypeClass(
JSContext* context) {
- JS::RootedObject prototype(context, GetPrototype(context));
+ JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+ DCHECK(global_object);
+
+ JS::RootedObject prototype(context, GetPrototype(context, global_object));
JSClass* proto_class = JS_GetClass(*prototype.address());
return proto_class;
}
// static
-JSObject* MozjsIndexedGetterInterface::GetPrototype(JSContext* context) {
+JSObject* MozjsIndexedGetterInterface::GetPrototype(
+ JSContext* context, JS::HandleObject global_object) {
+ DCHECK(JS_IsGlobalObject(global_object));
+
InterfaceData* interface_data = GetInterfaceData(context);
if (!interface_data->prototype) {
// Create new prototype that has all the props and methods
- InitializePrototypeAndInterfaceObject(interface_data, context);
+ InitializePrototypeAndInterfaceObject(
+ interface_data, context, global_object);
}
DCHECK(interface_data->prototype);
return interface_data->prototype;
}
// static
-JSObject* MozjsIndexedGetterInterface::GetInterfaceObject(JSContext* context) {
+JSObject* MozjsIndexedGetterInterface::GetInterfaceObject(
+ JSContext* context, JS::HandleObject global_object) {
+ DCHECK(JS_IsGlobalObject(global_object));
+
InterfaceData* interface_data = GetInterfaceData(context);
if (!interface_data->interface_object) {
- InitializePrototypeAndInterfaceObject(interface_data, context);
+ InitializePrototypeAndInterfaceObject(
+ interface_data, context, global_object);
}
DCHECK(interface_data->interface_object);
return interface_data->interface_object;
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsIndexedGetterInterface.h b/src/cobalt/bindings/generated/mozjs/testing/MozjsIndexedGetterInterface.h
index a61619c..28984fe 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsIndexedGetterInterface.h
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsIndexedGetterInterface.h
@@ -41,8 +41,10 @@
static JSObject* CreateProxy(JSContext* context,
const scoped_refptr<script::Wrappable>& wrappable);
static const JSClass* PrototypeClass(JSContext* context);
- static JSObject* GetPrototype(JSContext* context);
- static JSObject* GetInterfaceObject(JSContext* context);
+ static JSObject* GetPrototype(JSContext* context,
+ JS::HandleObject global_object);
+ static JSObject* GetInterfaceObject(JSContext* context,
+ JS::HandleObject global_object);
};
} // namespace bindings
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsInterfaceWithUnsupportedProperties.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsInterfaceWithUnsupportedProperties.cc
index 5831dae..d629315 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsInterfaceWithUnsupportedProperties.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsInterfaceWithUnsupportedProperties.cc
@@ -114,6 +114,26 @@
static base::LazyInstance<MozjsInterfaceWithUnsupportedPropertiesHandler>
proxy_handler;
+JSBool HasInstance(JSContext *context, JS::HandleObject type,
+ JS::MutableHandleValue vp, JSBool *success) {
+ JS::RootedObject global_object(
+ context, JS_GetGlobalForObject(context, type));
+ DCHECK(global_object);
+
+ JS::RootedObject prototype(
+ context, MozjsInterfaceWithUnsupportedProperties::GetPrototype(context, global_object));
+
+ // |IsDelegate| walks the prototype chain of an object returning true if
+ // .prototype is found.
+ bool is_delegate;
+ if (!IsDelegate(context, prototype, vp, &is_delegate)) {
+ *success = false;
+ return false;
+ }
+
+ *success = is_delegate;
+ return true;
+}
InterfaceData* CreateCachedInterfaceData() {
InterfaceData* interface_data = new InterfaceData();
@@ -162,6 +182,7 @@
interface_object_class->enumerate = JS_EnumerateStub;
interface_object_class->resolve = JS_ResolveStub;
interface_object_class->convert = JS_ConvertStub;
+ interface_object_class->hasInstance = &HasInstance;
return interface_data;
}
@@ -215,14 +236,12 @@
};
void InitializePrototypeAndInterfaceObject(
- InterfaceData* interface_data, JSContext* context) {
+ InterfaceData* interface_data, JSContext* context,
+ JS::HandleObject global_object) {
DCHECK(!interface_data->prototype);
DCHECK(!interface_data->interface_object);
+ DCHECK(JS_IsGlobalObject(global_object));
- MozjsGlobalObjectProxy* global_object_proxy =
- static_cast<MozjsGlobalObjectProxy*>(JS_GetContextPrivate(context));
- JS::RootedObject global_object(context, global_object_proxy->global_object());
- DCHECK(global_object);
JS::RootedObject parent_prototype(
context, JS_GetObjectPrototype(context, global_object));
DCHECK(parent_prototype);
@@ -301,8 +320,11 @@
// static
JSObject* MozjsInterfaceWithUnsupportedProperties::CreateProxy(
JSContext* context, const scoped_refptr<Wrappable>& wrappable) {
+ JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+ DCHECK(global_object);
+
InterfaceData* interface_data = GetInterfaceData(context);
- JS::RootedObject prototype(context, GetPrototype(context));
+ JS::RootedObject prototype(context, GetPrototype(context, global_object));
DCHECK(prototype);
JS::RootedObject new_object(context, JS_NewObjectWithGivenProto(
context, &interface_data->instance_class_definition, prototype, NULL));
@@ -310,34 +332,45 @@
JS::RootedObject proxy(context,
ProxyHandler::NewProxy(context, new_object, prototype, NULL,
proxy_handler.Pointer()));
- WrapperPrivate::AddPrivateData(proxy, wrappable);
+ WrapperPrivate::AddPrivateData(context, proxy, wrappable);
return proxy;
}
//static
const JSClass* MozjsInterfaceWithUnsupportedProperties::PrototypeClass(
JSContext* context) {
- JS::RootedObject prototype(context, GetPrototype(context));
+ JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+ DCHECK(global_object);
+
+ JS::RootedObject prototype(context, GetPrototype(context, global_object));
JSClass* proto_class = JS_GetClass(*prototype.address());
return proto_class;
}
// static
-JSObject* MozjsInterfaceWithUnsupportedProperties::GetPrototype(JSContext* context) {
+JSObject* MozjsInterfaceWithUnsupportedProperties::GetPrototype(
+ JSContext* context, JS::HandleObject global_object) {
+ DCHECK(JS_IsGlobalObject(global_object));
+
InterfaceData* interface_data = GetInterfaceData(context);
if (!interface_data->prototype) {
// Create new prototype that has all the props and methods
- InitializePrototypeAndInterfaceObject(interface_data, context);
+ InitializePrototypeAndInterfaceObject(
+ interface_data, context, global_object);
}
DCHECK(interface_data->prototype);
return interface_data->prototype;
}
// static
-JSObject* MozjsInterfaceWithUnsupportedProperties::GetInterfaceObject(JSContext* context) {
+JSObject* MozjsInterfaceWithUnsupportedProperties::GetInterfaceObject(
+ JSContext* context, JS::HandleObject global_object) {
+ DCHECK(JS_IsGlobalObject(global_object));
+
InterfaceData* interface_data = GetInterfaceData(context);
if (!interface_data->interface_object) {
- InitializePrototypeAndInterfaceObject(interface_data, context);
+ InitializePrototypeAndInterfaceObject(
+ interface_data, context, global_object);
}
DCHECK(interface_data->interface_object);
return interface_data->interface_object;
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsInterfaceWithUnsupportedProperties.h b/src/cobalt/bindings/generated/mozjs/testing/MozjsInterfaceWithUnsupportedProperties.h
index 417e204..24c2964 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsInterfaceWithUnsupportedProperties.h
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsInterfaceWithUnsupportedProperties.h
@@ -41,8 +41,10 @@
static JSObject* CreateProxy(JSContext* context,
const scoped_refptr<script::Wrappable>& wrappable);
static const JSClass* PrototypeClass(JSContext* context);
- static JSObject* GetPrototype(JSContext* context);
- static JSObject* GetInterfaceObject(JSContext* context);
+ static JSObject* GetPrototype(JSContext* context,
+ JS::HandleObject global_object);
+ static JSObject* GetInterfaceObject(JSContext* context,
+ JS::HandleObject global_object);
};
} // namespace bindings
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsNamedConstructorInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsNamedConstructorInterface.cc
index f0a1359..bdb7519 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsNamedConstructorInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsNamedConstructorInterface.cc
@@ -115,6 +115,26 @@
proxy_handler;
JSBool Constructor(JSContext* context, unsigned int argc, JS::Value* vp);
+JSBool HasInstance(JSContext *context, JS::HandleObject type,
+ JS::MutableHandleValue vp, JSBool *success) {
+ JS::RootedObject global_object(
+ context, JS_GetGlobalForObject(context, type));
+ DCHECK(global_object);
+
+ JS::RootedObject prototype(
+ context, MozjsNamedConstructorInterface::GetPrototype(context, global_object));
+
+ // |IsDelegate| walks the prototype chain of an object returning true if
+ // .prototype is found.
+ bool is_delegate;
+ if (!IsDelegate(context, prototype, vp, &is_delegate)) {
+ *success = false;
+ return false;
+ }
+
+ *success = is_delegate;
+ return true;
+}
InterfaceData* CreateCachedInterfaceData() {
InterfaceData* interface_data = new InterfaceData();
@@ -163,6 +183,7 @@
interface_object_class->enumerate = JS_EnumerateStub;
interface_object_class->resolve = JS_ResolveStub;
interface_object_class->convert = JS_ConvertStub;
+ interface_object_class->hasInstance = &HasInstance;
interface_object_class->construct = Constructor;
return interface_data;
}
@@ -189,14 +210,12 @@
};
void InitializePrototypeAndInterfaceObject(
- InterfaceData* interface_data, JSContext* context) {
+ InterfaceData* interface_data, JSContext* context,
+ JS::HandleObject global_object) {
DCHECK(!interface_data->prototype);
DCHECK(!interface_data->interface_object);
+ DCHECK(JS_IsGlobalObject(global_object));
- MozjsGlobalObjectProxy* global_object_proxy =
- static_cast<MozjsGlobalObjectProxy*>(JS_GetContextPrivate(context));
- JS::RootedObject global_object(context, global_object_proxy->global_object());
- DCHECK(global_object);
JS::RootedObject parent_prototype(
context, JS_GetObjectPrototype(context, global_object));
DCHECK(parent_prototype);
@@ -285,8 +304,11 @@
// static
JSObject* MozjsNamedConstructorInterface::CreateProxy(
JSContext* context, const scoped_refptr<Wrappable>& wrappable) {
+ JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+ DCHECK(global_object);
+
InterfaceData* interface_data = GetInterfaceData(context);
- JS::RootedObject prototype(context, GetPrototype(context));
+ JS::RootedObject prototype(context, GetPrototype(context, global_object));
DCHECK(prototype);
JS::RootedObject new_object(context, JS_NewObjectWithGivenProto(
context, &interface_data->instance_class_definition, prototype, NULL));
@@ -294,34 +316,45 @@
JS::RootedObject proxy(context,
ProxyHandler::NewProxy(context, new_object, prototype, NULL,
proxy_handler.Pointer()));
- WrapperPrivate::AddPrivateData(proxy, wrappable);
+ WrapperPrivate::AddPrivateData(context, proxy, wrappable);
return proxy;
}
//static
const JSClass* MozjsNamedConstructorInterface::PrototypeClass(
JSContext* context) {
- JS::RootedObject prototype(context, GetPrototype(context));
+ JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+ DCHECK(global_object);
+
+ JS::RootedObject prototype(context, GetPrototype(context, global_object));
JSClass* proto_class = JS_GetClass(*prototype.address());
return proto_class;
}
// static
-JSObject* MozjsNamedConstructorInterface::GetPrototype(JSContext* context) {
+JSObject* MozjsNamedConstructorInterface::GetPrototype(
+ JSContext* context, JS::HandleObject global_object) {
+ DCHECK(JS_IsGlobalObject(global_object));
+
InterfaceData* interface_data = GetInterfaceData(context);
if (!interface_data->prototype) {
// Create new prototype that has all the props and methods
- InitializePrototypeAndInterfaceObject(interface_data, context);
+ InitializePrototypeAndInterfaceObject(
+ interface_data, context, global_object);
}
DCHECK(interface_data->prototype);
return interface_data->prototype;
}
// static
-JSObject* MozjsNamedConstructorInterface::GetInterfaceObject(JSContext* context) {
+JSObject* MozjsNamedConstructorInterface::GetInterfaceObject(
+ JSContext* context, JS::HandleObject global_object) {
+ DCHECK(JS_IsGlobalObject(global_object));
+
InterfaceData* interface_data = GetInterfaceData(context);
if (!interface_data->interface_object) {
- InitializePrototypeAndInterfaceObject(interface_data, context);
+ InitializePrototypeAndInterfaceObject(
+ interface_data, context, global_object);
}
DCHECK(interface_data->interface_object);
return interface_data->interface_object;
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsNamedConstructorInterface.h b/src/cobalt/bindings/generated/mozjs/testing/MozjsNamedConstructorInterface.h
index 670e6fc..bee4c6b 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsNamedConstructorInterface.h
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsNamedConstructorInterface.h
@@ -41,8 +41,10 @@
static JSObject* CreateProxy(JSContext* context,
const scoped_refptr<script::Wrappable>& wrappable);
static const JSClass* PrototypeClass(JSContext* context);
- static JSObject* GetPrototype(JSContext* context);
- static JSObject* GetInterfaceObject(JSContext* context);
+ static JSObject* GetPrototype(JSContext* context,
+ JS::HandleObject global_object);
+ static JSObject* GetInterfaceObject(JSContext* context,
+ JS::HandleObject global_object);
};
} // namespace bindings
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsNamedGetterInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsNamedGetterInterface.cc
index d9debc4..f77d8de 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsNamedGetterInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsNamedGetterInterface.cc
@@ -220,6 +220,26 @@
static base::LazyInstance<MozjsNamedGetterInterfaceHandler>
proxy_handler;
+JSBool HasInstance(JSContext *context, JS::HandleObject type,
+ JS::MutableHandleValue vp, JSBool *success) {
+ JS::RootedObject global_object(
+ context, JS_GetGlobalForObject(context, type));
+ DCHECK(global_object);
+
+ JS::RootedObject prototype(
+ context, MozjsNamedGetterInterface::GetPrototype(context, global_object));
+
+ // |IsDelegate| walks the prototype chain of an object returning true if
+ // .prototype is found.
+ bool is_delegate;
+ if (!IsDelegate(context, prototype, vp, &is_delegate)) {
+ *success = false;
+ return false;
+ }
+
+ *success = is_delegate;
+ return true;
+}
InterfaceData* CreateCachedInterfaceData() {
InterfaceData* interface_data = new InterfaceData();
@@ -268,6 +288,7 @@
interface_object_class->enumerate = JS_EnumerateStub;
interface_object_class->resolve = JS_ResolveStub;
interface_object_class->convert = JS_ConvertStub;
+ interface_object_class->hasInstance = &HasInstance;
return interface_data;
}
@@ -473,14 +494,12 @@
};
void InitializePrototypeAndInterfaceObject(
- InterfaceData* interface_data, JSContext* context) {
+ InterfaceData* interface_data, JSContext* context,
+ JS::HandleObject global_object) {
DCHECK(!interface_data->prototype);
DCHECK(!interface_data->interface_object);
+ DCHECK(JS_IsGlobalObject(global_object));
- MozjsGlobalObjectProxy* global_object_proxy =
- static_cast<MozjsGlobalObjectProxy*>(JS_GetContextPrivate(context));
- JS::RootedObject global_object(context, global_object_proxy->global_object());
- DCHECK(global_object);
JS::RootedObject parent_prototype(
context, JS_GetObjectPrototype(context, global_object));
DCHECK(parent_prototype);
@@ -559,8 +578,11 @@
// static
JSObject* MozjsNamedGetterInterface::CreateProxy(
JSContext* context, const scoped_refptr<Wrappable>& wrappable) {
+ JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+ DCHECK(global_object);
+
InterfaceData* interface_data = GetInterfaceData(context);
- JS::RootedObject prototype(context, GetPrototype(context));
+ JS::RootedObject prototype(context, GetPrototype(context, global_object));
DCHECK(prototype);
JS::RootedObject new_object(context, JS_NewObjectWithGivenProto(
context, &interface_data->instance_class_definition, prototype, NULL));
@@ -568,34 +590,45 @@
JS::RootedObject proxy(context,
ProxyHandler::NewProxy(context, new_object, prototype, NULL,
proxy_handler.Pointer()));
- WrapperPrivate::AddPrivateData(proxy, wrappable);
+ WrapperPrivate::AddPrivateData(context, proxy, wrappable);
return proxy;
}
//static
const JSClass* MozjsNamedGetterInterface::PrototypeClass(
JSContext* context) {
- JS::RootedObject prototype(context, GetPrototype(context));
+ JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+ DCHECK(global_object);
+
+ JS::RootedObject prototype(context, GetPrototype(context, global_object));
JSClass* proto_class = JS_GetClass(*prototype.address());
return proto_class;
}
// static
-JSObject* MozjsNamedGetterInterface::GetPrototype(JSContext* context) {
+JSObject* MozjsNamedGetterInterface::GetPrototype(
+ JSContext* context, JS::HandleObject global_object) {
+ DCHECK(JS_IsGlobalObject(global_object));
+
InterfaceData* interface_data = GetInterfaceData(context);
if (!interface_data->prototype) {
// Create new prototype that has all the props and methods
- InitializePrototypeAndInterfaceObject(interface_data, context);
+ InitializePrototypeAndInterfaceObject(
+ interface_data, context, global_object);
}
DCHECK(interface_data->prototype);
return interface_data->prototype;
}
// static
-JSObject* MozjsNamedGetterInterface::GetInterfaceObject(JSContext* context) {
+JSObject* MozjsNamedGetterInterface::GetInterfaceObject(
+ JSContext* context, JS::HandleObject global_object) {
+ DCHECK(JS_IsGlobalObject(global_object));
+
InterfaceData* interface_data = GetInterfaceData(context);
if (!interface_data->interface_object) {
- InitializePrototypeAndInterfaceObject(interface_data, context);
+ InitializePrototypeAndInterfaceObject(
+ interface_data, context, global_object);
}
DCHECK(interface_data->interface_object);
return interface_data->interface_object;
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsNamedGetterInterface.h b/src/cobalt/bindings/generated/mozjs/testing/MozjsNamedGetterInterface.h
index 613c1b9..0d06347 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsNamedGetterInterface.h
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsNamedGetterInterface.h
@@ -41,8 +41,10 @@
static JSObject* CreateProxy(JSContext* context,
const scoped_refptr<script::Wrappable>& wrappable);
static const JSClass* PrototypeClass(JSContext* context);
- static JSObject* GetPrototype(JSContext* context);
- static JSObject* GetInterfaceObject(JSContext* context);
+ static JSObject* GetPrototype(JSContext* context,
+ JS::HandleObject global_object);
+ static JSObject* GetInterfaceObject(JSContext* context,
+ JS::HandleObject global_object);
};
} // namespace bindings
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsNamedIndexedGetterInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsNamedIndexedGetterInterface.cc
index e63ec48..bc60f6a 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsNamedIndexedGetterInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsNamedIndexedGetterInterface.cc
@@ -296,6 +296,26 @@
static base::LazyInstance<MozjsNamedIndexedGetterInterfaceHandler>
proxy_handler;
+JSBool HasInstance(JSContext *context, JS::HandleObject type,
+ JS::MutableHandleValue vp, JSBool *success) {
+ JS::RootedObject global_object(
+ context, JS_GetGlobalForObject(context, type));
+ DCHECK(global_object);
+
+ JS::RootedObject prototype(
+ context, MozjsNamedIndexedGetterInterface::GetPrototype(context, global_object));
+
+ // |IsDelegate| walks the prototype chain of an object returning true if
+ // .prototype is found.
+ bool is_delegate;
+ if (!IsDelegate(context, prototype, vp, &is_delegate)) {
+ *success = false;
+ return false;
+ }
+
+ *success = is_delegate;
+ return true;
+}
InterfaceData* CreateCachedInterfaceData() {
InterfaceData* interface_data = new InterfaceData();
@@ -344,6 +364,7 @@
interface_object_class->enumerate = JS_EnumerateStub;
interface_object_class->resolve = JS_ResolveStub;
interface_object_class->convert = JS_ConvertStub;
+ interface_object_class->hasInstance = &HasInstance;
return interface_data;
}
@@ -734,14 +755,12 @@
};
void InitializePrototypeAndInterfaceObject(
- InterfaceData* interface_data, JSContext* context) {
+ InterfaceData* interface_data, JSContext* context,
+ JS::HandleObject global_object) {
DCHECK(!interface_data->prototype);
DCHECK(!interface_data->interface_object);
+ DCHECK(JS_IsGlobalObject(global_object));
- MozjsGlobalObjectProxy* global_object_proxy =
- static_cast<MozjsGlobalObjectProxy*>(JS_GetContextPrivate(context));
- JS::RootedObject global_object(context, global_object_proxy->global_object());
- DCHECK(global_object);
JS::RootedObject parent_prototype(
context, JS_GetObjectPrototype(context, global_object));
DCHECK(parent_prototype);
@@ -820,8 +839,11 @@
// static
JSObject* MozjsNamedIndexedGetterInterface::CreateProxy(
JSContext* context, const scoped_refptr<Wrappable>& wrappable) {
+ JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+ DCHECK(global_object);
+
InterfaceData* interface_data = GetInterfaceData(context);
- JS::RootedObject prototype(context, GetPrototype(context));
+ JS::RootedObject prototype(context, GetPrototype(context, global_object));
DCHECK(prototype);
JS::RootedObject new_object(context, JS_NewObjectWithGivenProto(
context, &interface_data->instance_class_definition, prototype, NULL));
@@ -829,34 +851,45 @@
JS::RootedObject proxy(context,
ProxyHandler::NewProxy(context, new_object, prototype, NULL,
proxy_handler.Pointer()));
- WrapperPrivate::AddPrivateData(proxy, wrappable);
+ WrapperPrivate::AddPrivateData(context, proxy, wrappable);
return proxy;
}
//static
const JSClass* MozjsNamedIndexedGetterInterface::PrototypeClass(
JSContext* context) {
- JS::RootedObject prototype(context, GetPrototype(context));
+ JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+ DCHECK(global_object);
+
+ JS::RootedObject prototype(context, GetPrototype(context, global_object));
JSClass* proto_class = JS_GetClass(*prototype.address());
return proto_class;
}
// static
-JSObject* MozjsNamedIndexedGetterInterface::GetPrototype(JSContext* context) {
+JSObject* MozjsNamedIndexedGetterInterface::GetPrototype(
+ JSContext* context, JS::HandleObject global_object) {
+ DCHECK(JS_IsGlobalObject(global_object));
+
InterfaceData* interface_data = GetInterfaceData(context);
if (!interface_data->prototype) {
// Create new prototype that has all the props and methods
- InitializePrototypeAndInterfaceObject(interface_data, context);
+ InitializePrototypeAndInterfaceObject(
+ interface_data, context, global_object);
}
DCHECK(interface_data->prototype);
return interface_data->prototype;
}
// static
-JSObject* MozjsNamedIndexedGetterInterface::GetInterfaceObject(JSContext* context) {
+JSObject* MozjsNamedIndexedGetterInterface::GetInterfaceObject(
+ JSContext* context, JS::HandleObject global_object) {
+ DCHECK(JS_IsGlobalObject(global_object));
+
InterfaceData* interface_data = GetInterfaceData(context);
if (!interface_data->interface_object) {
- InitializePrototypeAndInterfaceObject(interface_data, context);
+ InitializePrototypeAndInterfaceObject(
+ interface_data, context, global_object);
}
DCHECK(interface_data->interface_object);
return interface_data->interface_object;
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsNamedIndexedGetterInterface.h b/src/cobalt/bindings/generated/mozjs/testing/MozjsNamedIndexedGetterInterface.h
index d0cc78a..ef5bbfa 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsNamedIndexedGetterInterface.h
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsNamedIndexedGetterInterface.h
@@ -41,8 +41,10 @@
static JSObject* CreateProxy(JSContext* context,
const scoped_refptr<script::Wrappable>& wrappable);
static const JSClass* PrototypeClass(JSContext* context);
- static JSObject* GetPrototype(JSContext* context);
- static JSObject* GetInterfaceObject(JSContext* context);
+ static JSObject* GetPrototype(JSContext* context,
+ JS::HandleObject global_object);
+ static JSObject* GetInterfaceObject(JSContext* context,
+ JS::HandleObject global_object);
};
} // namespace bindings
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsNestedPutForwardsInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsNestedPutForwardsInterface.cc
index e665fea..d30656e 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsNestedPutForwardsInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsNestedPutForwardsInterface.cc
@@ -118,6 +118,26 @@
static base::LazyInstance<MozjsNestedPutForwardsInterfaceHandler>
proxy_handler;
+JSBool HasInstance(JSContext *context, JS::HandleObject type,
+ JS::MutableHandleValue vp, JSBool *success) {
+ JS::RootedObject global_object(
+ context, JS_GetGlobalForObject(context, type));
+ DCHECK(global_object);
+
+ JS::RootedObject prototype(
+ context, MozjsNestedPutForwardsInterface::GetPrototype(context, global_object));
+
+ // |IsDelegate| walks the prototype chain of an object returning true if
+ // .prototype is found.
+ bool is_delegate;
+ if (!IsDelegate(context, prototype, vp, &is_delegate)) {
+ *success = false;
+ return false;
+ }
+
+ *success = is_delegate;
+ return true;
+}
InterfaceData* CreateCachedInterfaceData() {
InterfaceData* interface_data = new InterfaceData();
@@ -166,6 +186,7 @@
interface_object_class->enumerate = JS_EnumerateStub;
interface_object_class->resolve = JS_ResolveStub;
interface_object_class->convert = JS_ConvertStub;
+ interface_object_class->hasInstance = &HasInstance;
return interface_data;
}
@@ -263,14 +284,12 @@
};
void InitializePrototypeAndInterfaceObject(
- InterfaceData* interface_data, JSContext* context) {
+ InterfaceData* interface_data, JSContext* context,
+ JS::HandleObject global_object) {
DCHECK(!interface_data->prototype);
DCHECK(!interface_data->interface_object);
+ DCHECK(JS_IsGlobalObject(global_object));
- MozjsGlobalObjectProxy* global_object_proxy =
- static_cast<MozjsGlobalObjectProxy*>(JS_GetContextPrivate(context));
- JS::RootedObject global_object(context, global_object_proxy->global_object());
- DCHECK(global_object);
JS::RootedObject parent_prototype(
context, JS_GetObjectPrototype(context, global_object));
DCHECK(parent_prototype);
@@ -349,8 +368,11 @@
// static
JSObject* MozjsNestedPutForwardsInterface::CreateProxy(
JSContext* context, const scoped_refptr<Wrappable>& wrappable) {
+ JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+ DCHECK(global_object);
+
InterfaceData* interface_data = GetInterfaceData(context);
- JS::RootedObject prototype(context, GetPrototype(context));
+ JS::RootedObject prototype(context, GetPrototype(context, global_object));
DCHECK(prototype);
JS::RootedObject new_object(context, JS_NewObjectWithGivenProto(
context, &interface_data->instance_class_definition, prototype, NULL));
@@ -358,34 +380,45 @@
JS::RootedObject proxy(context,
ProxyHandler::NewProxy(context, new_object, prototype, NULL,
proxy_handler.Pointer()));
- WrapperPrivate::AddPrivateData(proxy, wrappable);
+ WrapperPrivate::AddPrivateData(context, proxy, wrappable);
return proxy;
}
//static
const JSClass* MozjsNestedPutForwardsInterface::PrototypeClass(
JSContext* context) {
- JS::RootedObject prototype(context, GetPrototype(context));
+ JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+ DCHECK(global_object);
+
+ JS::RootedObject prototype(context, GetPrototype(context, global_object));
JSClass* proto_class = JS_GetClass(*prototype.address());
return proto_class;
}
// static
-JSObject* MozjsNestedPutForwardsInterface::GetPrototype(JSContext* context) {
+JSObject* MozjsNestedPutForwardsInterface::GetPrototype(
+ JSContext* context, JS::HandleObject global_object) {
+ DCHECK(JS_IsGlobalObject(global_object));
+
InterfaceData* interface_data = GetInterfaceData(context);
if (!interface_data->prototype) {
// Create new prototype that has all the props and methods
- InitializePrototypeAndInterfaceObject(interface_data, context);
+ InitializePrototypeAndInterfaceObject(
+ interface_data, context, global_object);
}
DCHECK(interface_data->prototype);
return interface_data->prototype;
}
// static
-JSObject* MozjsNestedPutForwardsInterface::GetInterfaceObject(JSContext* context) {
+JSObject* MozjsNestedPutForwardsInterface::GetInterfaceObject(
+ JSContext* context, JS::HandleObject global_object) {
+ DCHECK(JS_IsGlobalObject(global_object));
+
InterfaceData* interface_data = GetInterfaceData(context);
if (!interface_data->interface_object) {
- InitializePrototypeAndInterfaceObject(interface_data, context);
+ InitializePrototypeAndInterfaceObject(
+ interface_data, context, global_object);
}
DCHECK(interface_data->interface_object);
return interface_data->interface_object;
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsNestedPutForwardsInterface.h b/src/cobalt/bindings/generated/mozjs/testing/MozjsNestedPutForwardsInterface.h
index 47b1965..50e0e3c 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsNestedPutForwardsInterface.h
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsNestedPutForwardsInterface.h
@@ -41,8 +41,10 @@
static JSObject* CreateProxy(JSContext* context,
const scoped_refptr<script::Wrappable>& wrappable);
static const JSClass* PrototypeClass(JSContext* context);
- static JSObject* GetPrototype(JSContext* context);
- static JSObject* GetInterfaceObject(JSContext* context);
+ static JSObject* GetPrototype(JSContext* context,
+ JS::HandleObject global_object);
+ static JSObject* GetInterfaceObject(JSContext* context,
+ JS::HandleObject global_object);
};
} // namespace bindings
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsNoConstructorInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsNoConstructorInterface.cc
index ecf9e98..1848abb 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsNoConstructorInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsNoConstructorInterface.cc
@@ -114,6 +114,26 @@
static base::LazyInstance<MozjsNoConstructorInterfaceHandler>
proxy_handler;
+JSBool HasInstance(JSContext *context, JS::HandleObject type,
+ JS::MutableHandleValue vp, JSBool *success) {
+ JS::RootedObject global_object(
+ context, JS_GetGlobalForObject(context, type));
+ DCHECK(global_object);
+
+ JS::RootedObject prototype(
+ context, MozjsNoConstructorInterface::GetPrototype(context, global_object));
+
+ // |IsDelegate| walks the prototype chain of an object returning true if
+ // .prototype is found.
+ bool is_delegate;
+ if (!IsDelegate(context, prototype, vp, &is_delegate)) {
+ *success = false;
+ return false;
+ }
+
+ *success = is_delegate;
+ return true;
+}
InterfaceData* CreateCachedInterfaceData() {
InterfaceData* interface_data = new InterfaceData();
@@ -162,6 +182,7 @@
interface_object_class->enumerate = JS_EnumerateStub;
interface_object_class->resolve = JS_ResolveStub;
interface_object_class->convert = JS_ConvertStub;
+ interface_object_class->hasInstance = &HasInstance;
return interface_data;
}
@@ -187,14 +208,12 @@
};
void InitializePrototypeAndInterfaceObject(
- InterfaceData* interface_data, JSContext* context) {
+ InterfaceData* interface_data, JSContext* context,
+ JS::HandleObject global_object) {
DCHECK(!interface_data->prototype);
DCHECK(!interface_data->interface_object);
+ DCHECK(JS_IsGlobalObject(global_object));
- MozjsGlobalObjectProxy* global_object_proxy =
- static_cast<MozjsGlobalObjectProxy*>(JS_GetContextPrivate(context));
- JS::RootedObject global_object(context, global_object_proxy->global_object());
- DCHECK(global_object);
JS::RootedObject parent_prototype(
context, JS_GetObjectPrototype(context, global_object));
DCHECK(parent_prototype);
@@ -273,8 +292,11 @@
// static
JSObject* MozjsNoConstructorInterface::CreateProxy(
JSContext* context, const scoped_refptr<Wrappable>& wrappable) {
+ JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+ DCHECK(global_object);
+
InterfaceData* interface_data = GetInterfaceData(context);
- JS::RootedObject prototype(context, GetPrototype(context));
+ JS::RootedObject prototype(context, GetPrototype(context, global_object));
DCHECK(prototype);
JS::RootedObject new_object(context, JS_NewObjectWithGivenProto(
context, &interface_data->instance_class_definition, prototype, NULL));
@@ -282,34 +304,45 @@
JS::RootedObject proxy(context,
ProxyHandler::NewProxy(context, new_object, prototype, NULL,
proxy_handler.Pointer()));
- WrapperPrivate::AddPrivateData(proxy, wrappable);
+ WrapperPrivate::AddPrivateData(context, proxy, wrappable);
return proxy;
}
//static
const JSClass* MozjsNoConstructorInterface::PrototypeClass(
JSContext* context) {
- JS::RootedObject prototype(context, GetPrototype(context));
+ JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+ DCHECK(global_object);
+
+ JS::RootedObject prototype(context, GetPrototype(context, global_object));
JSClass* proto_class = JS_GetClass(*prototype.address());
return proto_class;
}
// static
-JSObject* MozjsNoConstructorInterface::GetPrototype(JSContext* context) {
+JSObject* MozjsNoConstructorInterface::GetPrototype(
+ JSContext* context, JS::HandleObject global_object) {
+ DCHECK(JS_IsGlobalObject(global_object));
+
InterfaceData* interface_data = GetInterfaceData(context);
if (!interface_data->prototype) {
// Create new prototype that has all the props and methods
- InitializePrototypeAndInterfaceObject(interface_data, context);
+ InitializePrototypeAndInterfaceObject(
+ interface_data, context, global_object);
}
DCHECK(interface_data->prototype);
return interface_data->prototype;
}
// static
-JSObject* MozjsNoConstructorInterface::GetInterfaceObject(JSContext* context) {
+JSObject* MozjsNoConstructorInterface::GetInterfaceObject(
+ JSContext* context, JS::HandleObject global_object) {
+ DCHECK(JS_IsGlobalObject(global_object));
+
InterfaceData* interface_data = GetInterfaceData(context);
if (!interface_data->interface_object) {
- InitializePrototypeAndInterfaceObject(interface_data, context);
+ InitializePrototypeAndInterfaceObject(
+ interface_data, context, global_object);
}
DCHECK(interface_data->interface_object);
return interface_data->interface_object;
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsNoConstructorInterface.h b/src/cobalt/bindings/generated/mozjs/testing/MozjsNoConstructorInterface.h
index 1c2a1c8..8fe1474 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsNoConstructorInterface.h
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsNoConstructorInterface.h
@@ -41,8 +41,10 @@
static JSObject* CreateProxy(JSContext* context,
const scoped_refptr<script::Wrappable>& wrappable);
static const JSClass* PrototypeClass(JSContext* context);
- static JSObject* GetPrototype(JSContext* context);
- static JSObject* GetInterfaceObject(JSContext* context);
+ static JSObject* GetPrototype(JSContext* context,
+ JS::HandleObject global_object);
+ static JSObject* GetInterfaceObject(JSContext* context,
+ JS::HandleObject global_object);
};
} // namespace bindings
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsNoInterfaceObjectInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsNoInterfaceObjectInterface.cc
index 27d50a2..1ad2cbb 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsNoInterfaceObjectInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsNoInterfaceObjectInterface.cc
@@ -114,6 +114,26 @@
static base::LazyInstance<MozjsNoInterfaceObjectInterfaceHandler>
proxy_handler;
+JSBool HasInstance(JSContext *context, JS::HandleObject type,
+ JS::MutableHandleValue vp, JSBool *success) {
+ JS::RootedObject global_object(
+ context, JS_GetGlobalForObject(context, type));
+ DCHECK(global_object);
+
+ JS::RootedObject prototype(
+ context, MozjsNoInterfaceObjectInterface::GetPrototype(context, global_object));
+
+ // |IsDelegate| walks the prototype chain of an object returning true if
+ // .prototype is found.
+ bool is_delegate;
+ if (!IsDelegate(context, prototype, vp, &is_delegate)) {
+ *success = false;
+ return false;
+ }
+
+ *success = is_delegate;
+ return true;
+}
InterfaceData* CreateCachedInterfaceData() {
InterfaceData* interface_data = new InterfaceData();
@@ -162,6 +182,7 @@
interface_object_class->enumerate = JS_EnumerateStub;
interface_object_class->resolve = JS_ResolveStub;
interface_object_class->convert = JS_ConvertStub;
+ interface_object_class->hasInstance = &HasInstance;
return interface_data;
}
@@ -187,14 +208,12 @@
};
void InitializePrototypeAndInterfaceObject(
- InterfaceData* interface_data, JSContext* context) {
+ InterfaceData* interface_data, JSContext* context,
+ JS::HandleObject global_object) {
DCHECK(!interface_data->prototype);
DCHECK(!interface_data->interface_object);
+ DCHECK(JS_IsGlobalObject(global_object));
- MozjsGlobalObjectProxy* global_object_proxy =
- static_cast<MozjsGlobalObjectProxy*>(JS_GetContextPrivate(context));
- JS::RootedObject global_object(context, global_object_proxy->global_object());
- DCHECK(global_object);
JS::RootedObject parent_prototype(
context, JS_GetObjectPrototype(context, global_object));
DCHECK(parent_prototype);
@@ -233,8 +252,11 @@
// static
JSObject* MozjsNoInterfaceObjectInterface::CreateProxy(
JSContext* context, const scoped_refptr<Wrappable>& wrappable) {
+ JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+ DCHECK(global_object);
+
InterfaceData* interface_data = GetInterfaceData(context);
- JS::RootedObject prototype(context, GetPrototype(context));
+ JS::RootedObject prototype(context, GetPrototype(context, global_object));
DCHECK(prototype);
JS::RootedObject new_object(context, JS_NewObjectWithGivenProto(
context, &interface_data->instance_class_definition, prototype, NULL));
@@ -242,24 +264,31 @@
JS::RootedObject proxy(context,
ProxyHandler::NewProxy(context, new_object, prototype, NULL,
proxy_handler.Pointer()));
- WrapperPrivate::AddPrivateData(proxy, wrappable);
+ WrapperPrivate::AddPrivateData(context, proxy, wrappable);
return proxy;
}
//static
const JSClass* MozjsNoInterfaceObjectInterface::PrototypeClass(
JSContext* context) {
- JS::RootedObject prototype(context, GetPrototype(context));
+ JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+ DCHECK(global_object);
+
+ JS::RootedObject prototype(context, GetPrototype(context, global_object));
JSClass* proto_class = JS_GetClass(*prototype.address());
return proto_class;
}
// static
-JSObject* MozjsNoInterfaceObjectInterface::GetPrototype(JSContext* context) {
+JSObject* MozjsNoInterfaceObjectInterface::GetPrototype(
+ JSContext* context, JS::HandleObject global_object) {
+ DCHECK(JS_IsGlobalObject(global_object));
+
InterfaceData* interface_data = GetInterfaceData(context);
if (!interface_data->prototype) {
// Create new prototype that has all the props and methods
- InitializePrototypeAndInterfaceObject(interface_data, context);
+ InitializePrototypeAndInterfaceObject(
+ interface_data, context, global_object);
}
DCHECK(interface_data->prototype);
return interface_data->prototype;
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsNoInterfaceObjectInterface.h b/src/cobalt/bindings/generated/mozjs/testing/MozjsNoInterfaceObjectInterface.h
index 8d5c0f1..1d0061f 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsNoInterfaceObjectInterface.h
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsNoInterfaceObjectInterface.h
@@ -41,7 +41,8 @@
static JSObject* CreateProxy(JSContext* context,
const scoped_refptr<script::Wrappable>& wrappable);
static const JSClass* PrototypeClass(JSContext* context);
- static JSObject* GetPrototype(JSContext* context);
+ static JSObject* GetPrototype(JSContext* context,
+ JS::HandleObject global_object);
};
} // namespace bindings
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsNullableTypesTestInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsNullableTypesTestInterface.cc
index 3176045..04c7ec4 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsNullableTypesTestInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsNullableTypesTestInterface.cc
@@ -118,6 +118,26 @@
static base::LazyInstance<MozjsNullableTypesTestInterfaceHandler>
proxy_handler;
+JSBool HasInstance(JSContext *context, JS::HandleObject type,
+ JS::MutableHandleValue vp, JSBool *success) {
+ JS::RootedObject global_object(
+ context, JS_GetGlobalForObject(context, type));
+ DCHECK(global_object);
+
+ JS::RootedObject prototype(
+ context, MozjsNullableTypesTestInterface::GetPrototype(context, global_object));
+
+ // |IsDelegate| walks the prototype chain of an object returning true if
+ // .prototype is found.
+ bool is_delegate;
+ if (!IsDelegate(context, prototype, vp, &is_delegate)) {
+ *success = false;
+ return false;
+ }
+
+ *success = is_delegate;
+ return true;
+}
InterfaceData* CreateCachedInterfaceData() {
InterfaceData* interface_data = new InterfaceData();
@@ -166,6 +186,7 @@
interface_object_class->enumerate = JS_EnumerateStub;
interface_object_class->resolve = JS_ResolveStub;
interface_object_class->convert = JS_ConvertStub;
+ interface_object_class->hasInstance = &HasInstance;
return interface_data;
}
@@ -771,14 +792,12 @@
};
void InitializePrototypeAndInterfaceObject(
- InterfaceData* interface_data, JSContext* context) {
+ InterfaceData* interface_data, JSContext* context,
+ JS::HandleObject global_object) {
DCHECK(!interface_data->prototype);
DCHECK(!interface_data->interface_object);
+ DCHECK(JS_IsGlobalObject(global_object));
- MozjsGlobalObjectProxy* global_object_proxy =
- static_cast<MozjsGlobalObjectProxy*>(JS_GetContextPrivate(context));
- JS::RootedObject global_object(context, global_object_proxy->global_object());
- DCHECK(global_object);
JS::RootedObject parent_prototype(
context, JS_GetObjectPrototype(context, global_object));
DCHECK(parent_prototype);
@@ -857,8 +876,11 @@
// static
JSObject* MozjsNullableTypesTestInterface::CreateProxy(
JSContext* context, const scoped_refptr<Wrappable>& wrappable) {
+ JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+ DCHECK(global_object);
+
InterfaceData* interface_data = GetInterfaceData(context);
- JS::RootedObject prototype(context, GetPrototype(context));
+ JS::RootedObject prototype(context, GetPrototype(context, global_object));
DCHECK(prototype);
JS::RootedObject new_object(context, JS_NewObjectWithGivenProto(
context, &interface_data->instance_class_definition, prototype, NULL));
@@ -866,34 +888,45 @@
JS::RootedObject proxy(context,
ProxyHandler::NewProxy(context, new_object, prototype, NULL,
proxy_handler.Pointer()));
- WrapperPrivate::AddPrivateData(proxy, wrappable);
+ WrapperPrivate::AddPrivateData(context, proxy, wrappable);
return proxy;
}
//static
const JSClass* MozjsNullableTypesTestInterface::PrototypeClass(
JSContext* context) {
- JS::RootedObject prototype(context, GetPrototype(context));
+ JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+ DCHECK(global_object);
+
+ JS::RootedObject prototype(context, GetPrototype(context, global_object));
JSClass* proto_class = JS_GetClass(*prototype.address());
return proto_class;
}
// static
-JSObject* MozjsNullableTypesTestInterface::GetPrototype(JSContext* context) {
+JSObject* MozjsNullableTypesTestInterface::GetPrototype(
+ JSContext* context, JS::HandleObject global_object) {
+ DCHECK(JS_IsGlobalObject(global_object));
+
InterfaceData* interface_data = GetInterfaceData(context);
if (!interface_data->prototype) {
// Create new prototype that has all the props and methods
- InitializePrototypeAndInterfaceObject(interface_data, context);
+ InitializePrototypeAndInterfaceObject(
+ interface_data, context, global_object);
}
DCHECK(interface_data->prototype);
return interface_data->prototype;
}
// static
-JSObject* MozjsNullableTypesTestInterface::GetInterfaceObject(JSContext* context) {
+JSObject* MozjsNullableTypesTestInterface::GetInterfaceObject(
+ JSContext* context, JS::HandleObject global_object) {
+ DCHECK(JS_IsGlobalObject(global_object));
+
InterfaceData* interface_data = GetInterfaceData(context);
if (!interface_data->interface_object) {
- InitializePrototypeAndInterfaceObject(interface_data, context);
+ InitializePrototypeAndInterfaceObject(
+ interface_data, context, global_object);
}
DCHECK(interface_data->interface_object);
return interface_data->interface_object;
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsNullableTypesTestInterface.h b/src/cobalt/bindings/generated/mozjs/testing/MozjsNullableTypesTestInterface.h
index 69bfddd..7b7bcb2 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsNullableTypesTestInterface.h
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsNullableTypesTestInterface.h
@@ -41,8 +41,10 @@
static JSObject* CreateProxy(JSContext* context,
const scoped_refptr<script::Wrappable>& wrappable);
static const JSClass* PrototypeClass(JSContext* context);
- static JSObject* GetPrototype(JSContext* context);
- static JSObject* GetInterfaceObject(JSContext* context);
+ static JSObject* GetPrototype(JSContext* context,
+ JS::HandleObject global_object);
+ static JSObject* GetInterfaceObject(JSContext* context,
+ JS::HandleObject global_object);
};
} // namespace bindings
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsNumericTypesTestInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsNumericTypesTestInterface.cc
index bfa31b4..546ed1a 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsNumericTypesTestInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsNumericTypesTestInterface.cc
@@ -114,6 +114,26 @@
static base::LazyInstance<MozjsNumericTypesTestInterfaceHandler>
proxy_handler;
+JSBool HasInstance(JSContext *context, JS::HandleObject type,
+ JS::MutableHandleValue vp, JSBool *success) {
+ JS::RootedObject global_object(
+ context, JS_GetGlobalForObject(context, type));
+ DCHECK(global_object);
+
+ JS::RootedObject prototype(
+ context, MozjsNumericTypesTestInterface::GetPrototype(context, global_object));
+
+ // |IsDelegate| walks the prototype chain of an object returning true if
+ // .prototype is found.
+ bool is_delegate;
+ if (!IsDelegate(context, prototype, vp, &is_delegate)) {
+ *success = false;
+ return false;
+ }
+
+ *success = is_delegate;
+ return true;
+}
InterfaceData* CreateCachedInterfaceData() {
InterfaceData* interface_data = new InterfaceData();
@@ -162,6 +182,7 @@
interface_object_class->enumerate = JS_EnumerateStub;
interface_object_class->resolve = JS_ResolveStub;
interface_object_class->convert = JS_ConvertStub;
+ interface_object_class->hasInstance = &HasInstance;
return interface_data;
}
@@ -1637,14 +1658,12 @@
};
void InitializePrototypeAndInterfaceObject(
- InterfaceData* interface_data, JSContext* context) {
+ InterfaceData* interface_data, JSContext* context,
+ JS::HandleObject global_object) {
DCHECK(!interface_data->prototype);
DCHECK(!interface_data->interface_object);
+ DCHECK(JS_IsGlobalObject(global_object));
- MozjsGlobalObjectProxy* global_object_proxy =
- static_cast<MozjsGlobalObjectProxy*>(JS_GetContextPrivate(context));
- JS::RootedObject global_object(context, global_object_proxy->global_object());
- DCHECK(global_object);
JS::RootedObject parent_prototype(
context, JS_GetObjectPrototype(context, global_object));
DCHECK(parent_prototype);
@@ -1723,8 +1742,11 @@
// static
JSObject* MozjsNumericTypesTestInterface::CreateProxy(
JSContext* context, const scoped_refptr<Wrappable>& wrappable) {
+ JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+ DCHECK(global_object);
+
InterfaceData* interface_data = GetInterfaceData(context);
- JS::RootedObject prototype(context, GetPrototype(context));
+ JS::RootedObject prototype(context, GetPrototype(context, global_object));
DCHECK(prototype);
JS::RootedObject new_object(context, JS_NewObjectWithGivenProto(
context, &interface_data->instance_class_definition, prototype, NULL));
@@ -1732,34 +1754,45 @@
JS::RootedObject proxy(context,
ProxyHandler::NewProxy(context, new_object, prototype, NULL,
proxy_handler.Pointer()));
- WrapperPrivate::AddPrivateData(proxy, wrappable);
+ WrapperPrivate::AddPrivateData(context, proxy, wrappable);
return proxy;
}
//static
const JSClass* MozjsNumericTypesTestInterface::PrototypeClass(
JSContext* context) {
- JS::RootedObject prototype(context, GetPrototype(context));
+ JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+ DCHECK(global_object);
+
+ JS::RootedObject prototype(context, GetPrototype(context, global_object));
JSClass* proto_class = JS_GetClass(*prototype.address());
return proto_class;
}
// static
-JSObject* MozjsNumericTypesTestInterface::GetPrototype(JSContext* context) {
+JSObject* MozjsNumericTypesTestInterface::GetPrototype(
+ JSContext* context, JS::HandleObject global_object) {
+ DCHECK(JS_IsGlobalObject(global_object));
+
InterfaceData* interface_data = GetInterfaceData(context);
if (!interface_data->prototype) {
// Create new prototype that has all the props and methods
- InitializePrototypeAndInterfaceObject(interface_data, context);
+ InitializePrototypeAndInterfaceObject(
+ interface_data, context, global_object);
}
DCHECK(interface_data->prototype);
return interface_data->prototype;
}
// static
-JSObject* MozjsNumericTypesTestInterface::GetInterfaceObject(JSContext* context) {
+JSObject* MozjsNumericTypesTestInterface::GetInterfaceObject(
+ JSContext* context, JS::HandleObject global_object) {
+ DCHECK(JS_IsGlobalObject(global_object));
+
InterfaceData* interface_data = GetInterfaceData(context);
if (!interface_data->interface_object) {
- InitializePrototypeAndInterfaceObject(interface_data, context);
+ InitializePrototypeAndInterfaceObject(
+ interface_data, context, global_object);
}
DCHECK(interface_data->interface_object);
return interface_data->interface_object;
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsNumericTypesTestInterface.h b/src/cobalt/bindings/generated/mozjs/testing/MozjsNumericTypesTestInterface.h
index f33342b..e02d41a 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsNumericTypesTestInterface.h
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsNumericTypesTestInterface.h
@@ -41,8 +41,10 @@
static JSObject* CreateProxy(JSContext* context,
const scoped_refptr<script::Wrappable>& wrappable);
static const JSClass* PrototypeClass(JSContext* context);
- static JSObject* GetPrototype(JSContext* context);
- static JSObject* GetInterfaceObject(JSContext* context);
+ static JSObject* GetPrototype(JSContext* context,
+ JS::HandleObject global_object);
+ static JSObject* GetInterfaceObject(JSContext* context,
+ JS::HandleObject global_object);
};
} // namespace bindings
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsObjectTypeBindingsInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsObjectTypeBindingsInterface.cc
index 5e32d87..4dbc0b3 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsObjectTypeBindingsInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsObjectTypeBindingsInterface.cc
@@ -126,6 +126,26 @@
static base::LazyInstance<MozjsObjectTypeBindingsInterfaceHandler>
proxy_handler;
+JSBool HasInstance(JSContext *context, JS::HandleObject type,
+ JS::MutableHandleValue vp, JSBool *success) {
+ JS::RootedObject global_object(
+ context, JS_GetGlobalForObject(context, type));
+ DCHECK(global_object);
+
+ JS::RootedObject prototype(
+ context, MozjsObjectTypeBindingsInterface::GetPrototype(context, global_object));
+
+ // |IsDelegate| walks the prototype chain of an object returning true if
+ // .prototype is found.
+ bool is_delegate;
+ if (!IsDelegate(context, prototype, vp, &is_delegate)) {
+ *success = false;
+ return false;
+ }
+
+ *success = is_delegate;
+ return true;
+}
InterfaceData* CreateCachedInterfaceData() {
InterfaceData* interface_data = new InterfaceData();
@@ -174,6 +194,7 @@
interface_object_class->enumerate = JS_EnumerateStub;
interface_object_class->resolve = JS_ResolveStub;
interface_object_class->convert = JS_ConvertStub;
+ interface_object_class->hasInstance = &HasInstance;
return interface_data;
}
@@ -377,14 +398,12 @@
};
void InitializePrototypeAndInterfaceObject(
- InterfaceData* interface_data, JSContext* context) {
+ InterfaceData* interface_data, JSContext* context,
+ JS::HandleObject global_object) {
DCHECK(!interface_data->prototype);
DCHECK(!interface_data->interface_object);
+ DCHECK(JS_IsGlobalObject(global_object));
- MozjsGlobalObjectProxy* global_object_proxy =
- static_cast<MozjsGlobalObjectProxy*>(JS_GetContextPrivate(context));
- JS::RootedObject global_object(context, global_object_proxy->global_object());
- DCHECK(global_object);
JS::RootedObject parent_prototype(
context, JS_GetObjectPrototype(context, global_object));
DCHECK(parent_prototype);
@@ -463,8 +482,11 @@
// static
JSObject* MozjsObjectTypeBindingsInterface::CreateProxy(
JSContext* context, const scoped_refptr<Wrappable>& wrappable) {
+ JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+ DCHECK(global_object);
+
InterfaceData* interface_data = GetInterfaceData(context);
- JS::RootedObject prototype(context, GetPrototype(context));
+ JS::RootedObject prototype(context, GetPrototype(context, global_object));
DCHECK(prototype);
JS::RootedObject new_object(context, JS_NewObjectWithGivenProto(
context, &interface_data->instance_class_definition, prototype, NULL));
@@ -472,34 +494,45 @@
JS::RootedObject proxy(context,
ProxyHandler::NewProxy(context, new_object, prototype, NULL,
proxy_handler.Pointer()));
- WrapperPrivate::AddPrivateData(proxy, wrappable);
+ WrapperPrivate::AddPrivateData(context, proxy, wrappable);
return proxy;
}
//static
const JSClass* MozjsObjectTypeBindingsInterface::PrototypeClass(
JSContext* context) {
- JS::RootedObject prototype(context, GetPrototype(context));
+ JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+ DCHECK(global_object);
+
+ JS::RootedObject prototype(context, GetPrototype(context, global_object));
JSClass* proto_class = JS_GetClass(*prototype.address());
return proto_class;
}
// static
-JSObject* MozjsObjectTypeBindingsInterface::GetPrototype(JSContext* context) {
+JSObject* MozjsObjectTypeBindingsInterface::GetPrototype(
+ JSContext* context, JS::HandleObject global_object) {
+ DCHECK(JS_IsGlobalObject(global_object));
+
InterfaceData* interface_data = GetInterfaceData(context);
if (!interface_data->prototype) {
// Create new prototype that has all the props and methods
- InitializePrototypeAndInterfaceObject(interface_data, context);
+ InitializePrototypeAndInterfaceObject(
+ interface_data, context, global_object);
}
DCHECK(interface_data->prototype);
return interface_data->prototype;
}
// static
-JSObject* MozjsObjectTypeBindingsInterface::GetInterfaceObject(JSContext* context) {
+JSObject* MozjsObjectTypeBindingsInterface::GetInterfaceObject(
+ JSContext* context, JS::HandleObject global_object) {
+ DCHECK(JS_IsGlobalObject(global_object));
+
InterfaceData* interface_data = GetInterfaceData(context);
if (!interface_data->interface_object) {
- InitializePrototypeAndInterfaceObject(interface_data, context);
+ InitializePrototypeAndInterfaceObject(
+ interface_data, context, global_object);
}
DCHECK(interface_data->interface_object);
return interface_data->interface_object;
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsObjectTypeBindingsInterface.h b/src/cobalt/bindings/generated/mozjs/testing/MozjsObjectTypeBindingsInterface.h
index 27aa23c..8ae6e03 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsObjectTypeBindingsInterface.h
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsObjectTypeBindingsInterface.h
@@ -41,8 +41,10 @@
static JSObject* CreateProxy(JSContext* context,
const scoped_refptr<script::Wrappable>& wrappable);
static const JSClass* PrototypeClass(JSContext* context);
- static JSObject* GetPrototype(JSContext* context);
- static JSObject* GetInterfaceObject(JSContext* context);
+ static JSObject* GetPrototype(JSContext* context,
+ JS::HandleObject global_object);
+ static JSObject* GetInterfaceObject(JSContext* context,
+ JS::HandleObject global_object);
};
} // namespace bindings
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsOperationsTestInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsOperationsTestInterface.cc
index 473b292..7d9c1b0 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsOperationsTestInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsOperationsTestInterface.cc
@@ -118,6 +118,26 @@
static base::LazyInstance<MozjsOperationsTestInterfaceHandler>
proxy_handler;
+JSBool HasInstance(JSContext *context, JS::HandleObject type,
+ JS::MutableHandleValue vp, JSBool *success) {
+ JS::RootedObject global_object(
+ context, JS_GetGlobalForObject(context, type));
+ DCHECK(global_object);
+
+ JS::RootedObject prototype(
+ context, MozjsOperationsTestInterface::GetPrototype(context, global_object));
+
+ // |IsDelegate| walks the prototype chain of an object returning true if
+ // .prototype is found.
+ bool is_delegate;
+ if (!IsDelegate(context, prototype, vp, &is_delegate)) {
+ *success = false;
+ return false;
+ }
+
+ *success = is_delegate;
+ return true;
+}
InterfaceData* CreateCachedInterfaceData() {
InterfaceData* interface_data = new InterfaceData();
@@ -166,6 +186,7 @@
interface_object_class->enumerate = JS_EnumerateStub;
interface_object_class->resolve = JS_ResolveStub;
interface_object_class->convert = JS_ConvertStub;
+ interface_object_class->hasInstance = &HasInstance;
return interface_data;
}
@@ -1460,14 +1481,12 @@
};
void InitializePrototypeAndInterfaceObject(
- InterfaceData* interface_data, JSContext* context) {
+ InterfaceData* interface_data, JSContext* context,
+ JS::HandleObject global_object) {
DCHECK(!interface_data->prototype);
DCHECK(!interface_data->interface_object);
+ DCHECK(JS_IsGlobalObject(global_object));
- MozjsGlobalObjectProxy* global_object_proxy =
- static_cast<MozjsGlobalObjectProxy*>(JS_GetContextPrivate(context));
- JS::RootedObject global_object(context, global_object_proxy->global_object());
- DCHECK(global_object);
JS::RootedObject parent_prototype(
context, JS_GetObjectPrototype(context, global_object));
DCHECK(parent_prototype);
@@ -1546,8 +1565,11 @@
// static
JSObject* MozjsOperationsTestInterface::CreateProxy(
JSContext* context, const scoped_refptr<Wrappable>& wrappable) {
+ JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+ DCHECK(global_object);
+
InterfaceData* interface_data = GetInterfaceData(context);
- JS::RootedObject prototype(context, GetPrototype(context));
+ JS::RootedObject prototype(context, GetPrototype(context, global_object));
DCHECK(prototype);
JS::RootedObject new_object(context, JS_NewObjectWithGivenProto(
context, &interface_data->instance_class_definition, prototype, NULL));
@@ -1555,34 +1577,45 @@
JS::RootedObject proxy(context,
ProxyHandler::NewProxy(context, new_object, prototype, NULL,
proxy_handler.Pointer()));
- WrapperPrivate::AddPrivateData(proxy, wrappable);
+ WrapperPrivate::AddPrivateData(context, proxy, wrappable);
return proxy;
}
//static
const JSClass* MozjsOperationsTestInterface::PrototypeClass(
JSContext* context) {
- JS::RootedObject prototype(context, GetPrototype(context));
+ JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+ DCHECK(global_object);
+
+ JS::RootedObject prototype(context, GetPrototype(context, global_object));
JSClass* proto_class = JS_GetClass(*prototype.address());
return proto_class;
}
// static
-JSObject* MozjsOperationsTestInterface::GetPrototype(JSContext* context) {
+JSObject* MozjsOperationsTestInterface::GetPrototype(
+ JSContext* context, JS::HandleObject global_object) {
+ DCHECK(JS_IsGlobalObject(global_object));
+
InterfaceData* interface_data = GetInterfaceData(context);
if (!interface_data->prototype) {
// Create new prototype that has all the props and methods
- InitializePrototypeAndInterfaceObject(interface_data, context);
+ InitializePrototypeAndInterfaceObject(
+ interface_data, context, global_object);
}
DCHECK(interface_data->prototype);
return interface_data->prototype;
}
// static
-JSObject* MozjsOperationsTestInterface::GetInterfaceObject(JSContext* context) {
+JSObject* MozjsOperationsTestInterface::GetInterfaceObject(
+ JSContext* context, JS::HandleObject global_object) {
+ DCHECK(JS_IsGlobalObject(global_object));
+
InterfaceData* interface_data = GetInterfaceData(context);
if (!interface_data->interface_object) {
- InitializePrototypeAndInterfaceObject(interface_data, context);
+ InitializePrototypeAndInterfaceObject(
+ interface_data, context, global_object);
}
DCHECK(interface_data->interface_object);
return interface_data->interface_object;
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsOperationsTestInterface.h b/src/cobalt/bindings/generated/mozjs/testing/MozjsOperationsTestInterface.h
index d0e54e1..3968437 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsOperationsTestInterface.h
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsOperationsTestInterface.h
@@ -41,8 +41,10 @@
static JSObject* CreateProxy(JSContext* context,
const scoped_refptr<script::Wrappable>& wrappable);
static const JSClass* PrototypeClass(JSContext* context);
- static JSObject* GetPrototype(JSContext* context);
- static JSObject* GetInterfaceObject(JSContext* context);
+ static JSObject* GetPrototype(JSContext* context,
+ JS::HandleObject global_object);
+ static JSObject* GetInterfaceObject(JSContext* context,
+ JS::HandleObject global_object);
};
} // namespace bindings
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsPutForwardsInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsPutForwardsInterface.cc
index b977879..c632988 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsPutForwardsInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsPutForwardsInterface.cc
@@ -118,6 +118,26 @@
static base::LazyInstance<MozjsPutForwardsInterfaceHandler>
proxy_handler;
+JSBool HasInstance(JSContext *context, JS::HandleObject type,
+ JS::MutableHandleValue vp, JSBool *success) {
+ JS::RootedObject global_object(
+ context, JS_GetGlobalForObject(context, type));
+ DCHECK(global_object);
+
+ JS::RootedObject prototype(
+ context, MozjsPutForwardsInterface::GetPrototype(context, global_object));
+
+ // |IsDelegate| walks the prototype chain of an object returning true if
+ // .prototype is found.
+ bool is_delegate;
+ if (!IsDelegate(context, prototype, vp, &is_delegate)) {
+ *success = false;
+ return false;
+ }
+
+ *success = is_delegate;
+ return true;
+}
InterfaceData* CreateCachedInterfaceData() {
InterfaceData* interface_data = new InterfaceData();
@@ -166,6 +186,7 @@
interface_object_class->enumerate = JS_EnumerateStub;
interface_object_class->resolve = JS_ResolveStub;
interface_object_class->convert = JS_ConvertStub;
+ interface_object_class->hasInstance = &HasInstance;
return interface_data;
}
@@ -304,14 +325,12 @@
};
void InitializePrototypeAndInterfaceObject(
- InterfaceData* interface_data, JSContext* context) {
+ InterfaceData* interface_data, JSContext* context,
+ JS::HandleObject global_object) {
DCHECK(!interface_data->prototype);
DCHECK(!interface_data->interface_object);
+ DCHECK(JS_IsGlobalObject(global_object));
- MozjsGlobalObjectProxy* global_object_proxy =
- static_cast<MozjsGlobalObjectProxy*>(JS_GetContextPrivate(context));
- JS::RootedObject global_object(context, global_object_proxy->global_object());
- DCHECK(global_object);
JS::RootedObject parent_prototype(
context, JS_GetObjectPrototype(context, global_object));
DCHECK(parent_prototype);
@@ -390,8 +409,11 @@
// static
JSObject* MozjsPutForwardsInterface::CreateProxy(
JSContext* context, const scoped_refptr<Wrappable>& wrappable) {
+ JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+ DCHECK(global_object);
+
InterfaceData* interface_data = GetInterfaceData(context);
- JS::RootedObject prototype(context, GetPrototype(context));
+ JS::RootedObject prototype(context, GetPrototype(context, global_object));
DCHECK(prototype);
JS::RootedObject new_object(context, JS_NewObjectWithGivenProto(
context, &interface_data->instance_class_definition, prototype, NULL));
@@ -399,34 +421,45 @@
JS::RootedObject proxy(context,
ProxyHandler::NewProxy(context, new_object, prototype, NULL,
proxy_handler.Pointer()));
- WrapperPrivate::AddPrivateData(proxy, wrappable);
+ WrapperPrivate::AddPrivateData(context, proxy, wrappable);
return proxy;
}
//static
const JSClass* MozjsPutForwardsInterface::PrototypeClass(
JSContext* context) {
- JS::RootedObject prototype(context, GetPrototype(context));
+ JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+ DCHECK(global_object);
+
+ JS::RootedObject prototype(context, GetPrototype(context, global_object));
JSClass* proto_class = JS_GetClass(*prototype.address());
return proto_class;
}
// static
-JSObject* MozjsPutForwardsInterface::GetPrototype(JSContext* context) {
+JSObject* MozjsPutForwardsInterface::GetPrototype(
+ JSContext* context, JS::HandleObject global_object) {
+ DCHECK(JS_IsGlobalObject(global_object));
+
InterfaceData* interface_data = GetInterfaceData(context);
if (!interface_data->prototype) {
// Create new prototype that has all the props and methods
- InitializePrototypeAndInterfaceObject(interface_data, context);
+ InitializePrototypeAndInterfaceObject(
+ interface_data, context, global_object);
}
DCHECK(interface_data->prototype);
return interface_data->prototype;
}
// static
-JSObject* MozjsPutForwardsInterface::GetInterfaceObject(JSContext* context) {
+JSObject* MozjsPutForwardsInterface::GetInterfaceObject(
+ JSContext* context, JS::HandleObject global_object) {
+ DCHECK(JS_IsGlobalObject(global_object));
+
InterfaceData* interface_data = GetInterfaceData(context);
if (!interface_data->interface_object) {
- InitializePrototypeAndInterfaceObject(interface_data, context);
+ InitializePrototypeAndInterfaceObject(
+ interface_data, context, global_object);
}
DCHECK(interface_data->interface_object);
return interface_data->interface_object;
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsPutForwardsInterface.h b/src/cobalt/bindings/generated/mozjs/testing/MozjsPutForwardsInterface.h
index 06a6435..f0f5881 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsPutForwardsInterface.h
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsPutForwardsInterface.h
@@ -41,8 +41,10 @@
static JSObject* CreateProxy(JSContext* context,
const scoped_refptr<script::Wrappable>& wrappable);
static const JSClass* PrototypeClass(JSContext* context);
- static JSObject* GetPrototype(JSContext* context);
- static JSObject* GetInterfaceObject(JSContext* context);
+ static JSObject* GetPrototype(JSContext* context,
+ JS::HandleObject global_object);
+ static JSObject* GetInterfaceObject(JSContext* context,
+ JS::HandleObject global_object);
};
} // namespace bindings
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsStaticPropertiesInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsStaticPropertiesInterface.cc
index 210586c..7cd708f 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsStaticPropertiesInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsStaticPropertiesInterface.cc
@@ -118,6 +118,26 @@
static base::LazyInstance<MozjsStaticPropertiesInterfaceHandler>
proxy_handler;
+JSBool HasInstance(JSContext *context, JS::HandleObject type,
+ JS::MutableHandleValue vp, JSBool *success) {
+ JS::RootedObject global_object(
+ context, JS_GetGlobalForObject(context, type));
+ DCHECK(global_object);
+
+ JS::RootedObject prototype(
+ context, MozjsStaticPropertiesInterface::GetPrototype(context, global_object));
+
+ // |IsDelegate| walks the prototype chain of an object returning true if
+ // .prototype is found.
+ bool is_delegate;
+ if (!IsDelegate(context, prototype, vp, &is_delegate)) {
+ *success = false;
+ return false;
+ }
+
+ *success = is_delegate;
+ return true;
+}
InterfaceData* CreateCachedInterfaceData() {
InterfaceData* interface_data = new InterfaceData();
@@ -166,6 +186,7 @@
interface_object_class->enumerate = JS_EnumerateStub;
interface_object_class->resolve = JS_ResolveStub;
interface_object_class->convert = JS_ConvertStub;
+ interface_object_class->hasInstance = &HasInstance;
return interface_data;
}
@@ -486,14 +507,12 @@
};
void InitializePrototypeAndInterfaceObject(
- InterfaceData* interface_data, JSContext* context) {
+ InterfaceData* interface_data, JSContext* context,
+ JS::HandleObject global_object) {
DCHECK(!interface_data->prototype);
DCHECK(!interface_data->interface_object);
+ DCHECK(JS_IsGlobalObject(global_object));
- MozjsGlobalObjectProxy* global_object_proxy =
- static_cast<MozjsGlobalObjectProxy*>(JS_GetContextPrivate(context));
- JS::RootedObject global_object(context, global_object_proxy->global_object());
- DCHECK(global_object);
JS::RootedObject parent_prototype(
context, JS_GetObjectPrototype(context, global_object));
DCHECK(parent_prototype);
@@ -572,8 +591,11 @@
// static
JSObject* MozjsStaticPropertiesInterface::CreateProxy(
JSContext* context, const scoped_refptr<Wrappable>& wrappable) {
+ JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+ DCHECK(global_object);
+
InterfaceData* interface_data = GetInterfaceData(context);
- JS::RootedObject prototype(context, GetPrototype(context));
+ JS::RootedObject prototype(context, GetPrototype(context, global_object));
DCHECK(prototype);
JS::RootedObject new_object(context, JS_NewObjectWithGivenProto(
context, &interface_data->instance_class_definition, prototype, NULL));
@@ -581,34 +603,45 @@
JS::RootedObject proxy(context,
ProxyHandler::NewProxy(context, new_object, prototype, NULL,
proxy_handler.Pointer()));
- WrapperPrivate::AddPrivateData(proxy, wrappable);
+ WrapperPrivate::AddPrivateData(context, proxy, wrappable);
return proxy;
}
//static
const JSClass* MozjsStaticPropertiesInterface::PrototypeClass(
JSContext* context) {
- JS::RootedObject prototype(context, GetPrototype(context));
+ JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+ DCHECK(global_object);
+
+ JS::RootedObject prototype(context, GetPrototype(context, global_object));
JSClass* proto_class = JS_GetClass(*prototype.address());
return proto_class;
}
// static
-JSObject* MozjsStaticPropertiesInterface::GetPrototype(JSContext* context) {
+JSObject* MozjsStaticPropertiesInterface::GetPrototype(
+ JSContext* context, JS::HandleObject global_object) {
+ DCHECK(JS_IsGlobalObject(global_object));
+
InterfaceData* interface_data = GetInterfaceData(context);
if (!interface_data->prototype) {
// Create new prototype that has all the props and methods
- InitializePrototypeAndInterfaceObject(interface_data, context);
+ InitializePrototypeAndInterfaceObject(
+ interface_data, context, global_object);
}
DCHECK(interface_data->prototype);
return interface_data->prototype;
}
// static
-JSObject* MozjsStaticPropertiesInterface::GetInterfaceObject(JSContext* context) {
+JSObject* MozjsStaticPropertiesInterface::GetInterfaceObject(
+ JSContext* context, JS::HandleObject global_object) {
+ DCHECK(JS_IsGlobalObject(global_object));
+
InterfaceData* interface_data = GetInterfaceData(context);
if (!interface_data->interface_object) {
- InitializePrototypeAndInterfaceObject(interface_data, context);
+ InitializePrototypeAndInterfaceObject(
+ interface_data, context, global_object);
}
DCHECK(interface_data->interface_object);
return interface_data->interface_object;
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsStaticPropertiesInterface.h b/src/cobalt/bindings/generated/mozjs/testing/MozjsStaticPropertiesInterface.h
index db46890..27cb5e2 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsStaticPropertiesInterface.h
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsStaticPropertiesInterface.h
@@ -41,8 +41,10 @@
static JSObject* CreateProxy(JSContext* context,
const scoped_refptr<script::Wrappable>& wrappable);
static const JSClass* PrototypeClass(JSContext* context);
- static JSObject* GetPrototype(JSContext* context);
- static JSObject* GetInterfaceObject(JSContext* context);
+ static JSObject* GetPrototype(JSContext* context,
+ JS::HandleObject global_object);
+ static JSObject* GetInterfaceObject(JSContext* context,
+ JS::HandleObject global_object);
};
} // namespace bindings
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsStringifierAnonymousOperationInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsStringifierAnonymousOperationInterface.cc
index d77b60e..2471dfc 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsStringifierAnonymousOperationInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsStringifierAnonymousOperationInterface.cc
@@ -114,6 +114,26 @@
static base::LazyInstance<MozjsStringifierAnonymousOperationInterfaceHandler>
proxy_handler;
+JSBool HasInstance(JSContext *context, JS::HandleObject type,
+ JS::MutableHandleValue vp, JSBool *success) {
+ JS::RootedObject global_object(
+ context, JS_GetGlobalForObject(context, type));
+ DCHECK(global_object);
+
+ JS::RootedObject prototype(
+ context, MozjsStringifierAnonymousOperationInterface::GetPrototype(context, global_object));
+
+ // |IsDelegate| walks the prototype chain of an object returning true if
+ // .prototype is found.
+ bool is_delegate;
+ if (!IsDelegate(context, prototype, vp, &is_delegate)) {
+ *success = false;
+ return false;
+ }
+
+ *success = is_delegate;
+ return true;
+}
InterfaceData* CreateCachedInterfaceData() {
InterfaceData* interface_data = new InterfaceData();
@@ -162,6 +182,7 @@
interface_object_class->enumerate = JS_EnumerateStub;
interface_object_class->resolve = JS_ResolveStub;
interface_object_class->convert = JS_ConvertStub;
+ interface_object_class->hasInstance = &HasInstance;
return interface_data;
}
@@ -226,14 +247,12 @@
};
void InitializePrototypeAndInterfaceObject(
- InterfaceData* interface_data, JSContext* context) {
+ InterfaceData* interface_data, JSContext* context,
+ JS::HandleObject global_object) {
DCHECK(!interface_data->prototype);
DCHECK(!interface_data->interface_object);
+ DCHECK(JS_IsGlobalObject(global_object));
- MozjsGlobalObjectProxy* global_object_proxy =
- static_cast<MozjsGlobalObjectProxy*>(JS_GetContextPrivate(context));
- JS::RootedObject global_object(context, global_object_proxy->global_object());
- DCHECK(global_object);
JS::RootedObject parent_prototype(
context, JS_GetObjectPrototype(context, global_object));
DCHECK(parent_prototype);
@@ -312,8 +331,11 @@
// static
JSObject* MozjsStringifierAnonymousOperationInterface::CreateProxy(
JSContext* context, const scoped_refptr<Wrappable>& wrappable) {
+ JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+ DCHECK(global_object);
+
InterfaceData* interface_data = GetInterfaceData(context);
- JS::RootedObject prototype(context, GetPrototype(context));
+ JS::RootedObject prototype(context, GetPrototype(context, global_object));
DCHECK(prototype);
JS::RootedObject new_object(context, JS_NewObjectWithGivenProto(
context, &interface_data->instance_class_definition, prototype, NULL));
@@ -321,34 +343,45 @@
JS::RootedObject proxy(context,
ProxyHandler::NewProxy(context, new_object, prototype, NULL,
proxy_handler.Pointer()));
- WrapperPrivate::AddPrivateData(proxy, wrappable);
+ WrapperPrivate::AddPrivateData(context, proxy, wrappable);
return proxy;
}
//static
const JSClass* MozjsStringifierAnonymousOperationInterface::PrototypeClass(
JSContext* context) {
- JS::RootedObject prototype(context, GetPrototype(context));
+ JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+ DCHECK(global_object);
+
+ JS::RootedObject prototype(context, GetPrototype(context, global_object));
JSClass* proto_class = JS_GetClass(*prototype.address());
return proto_class;
}
// static
-JSObject* MozjsStringifierAnonymousOperationInterface::GetPrototype(JSContext* context) {
+JSObject* MozjsStringifierAnonymousOperationInterface::GetPrototype(
+ JSContext* context, JS::HandleObject global_object) {
+ DCHECK(JS_IsGlobalObject(global_object));
+
InterfaceData* interface_data = GetInterfaceData(context);
if (!interface_data->prototype) {
// Create new prototype that has all the props and methods
- InitializePrototypeAndInterfaceObject(interface_data, context);
+ InitializePrototypeAndInterfaceObject(
+ interface_data, context, global_object);
}
DCHECK(interface_data->prototype);
return interface_data->prototype;
}
// static
-JSObject* MozjsStringifierAnonymousOperationInterface::GetInterfaceObject(JSContext* context) {
+JSObject* MozjsStringifierAnonymousOperationInterface::GetInterfaceObject(
+ JSContext* context, JS::HandleObject global_object) {
+ DCHECK(JS_IsGlobalObject(global_object));
+
InterfaceData* interface_data = GetInterfaceData(context);
if (!interface_data->interface_object) {
- InitializePrototypeAndInterfaceObject(interface_data, context);
+ InitializePrototypeAndInterfaceObject(
+ interface_data, context, global_object);
}
DCHECK(interface_data->interface_object);
return interface_data->interface_object;
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsStringifierAnonymousOperationInterface.h b/src/cobalt/bindings/generated/mozjs/testing/MozjsStringifierAnonymousOperationInterface.h
index 0115c6a..b18e5a5 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsStringifierAnonymousOperationInterface.h
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsStringifierAnonymousOperationInterface.h
@@ -41,8 +41,10 @@
static JSObject* CreateProxy(JSContext* context,
const scoped_refptr<script::Wrappable>& wrappable);
static const JSClass* PrototypeClass(JSContext* context);
- static JSObject* GetPrototype(JSContext* context);
- static JSObject* GetInterfaceObject(JSContext* context);
+ static JSObject* GetPrototype(JSContext* context,
+ JS::HandleObject global_object);
+ static JSObject* GetInterfaceObject(JSContext* context,
+ JS::HandleObject global_object);
};
} // namespace bindings
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsStringifierAttributeInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsStringifierAttributeInterface.cc
index d652475..f97b025 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsStringifierAttributeInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsStringifierAttributeInterface.cc
@@ -114,6 +114,26 @@
static base::LazyInstance<MozjsStringifierAttributeInterfaceHandler>
proxy_handler;
+JSBool HasInstance(JSContext *context, JS::HandleObject type,
+ JS::MutableHandleValue vp, JSBool *success) {
+ JS::RootedObject global_object(
+ context, JS_GetGlobalForObject(context, type));
+ DCHECK(global_object);
+
+ JS::RootedObject prototype(
+ context, MozjsStringifierAttributeInterface::GetPrototype(context, global_object));
+
+ // |IsDelegate| walks the prototype chain of an object returning true if
+ // .prototype is found.
+ bool is_delegate;
+ if (!IsDelegate(context, prototype, vp, &is_delegate)) {
+ *success = false;
+ return false;
+ }
+
+ *success = is_delegate;
+ return true;
+}
InterfaceData* CreateCachedInterfaceData() {
InterfaceData* interface_data = new InterfaceData();
@@ -162,6 +182,7 @@
interface_object_class->enumerate = JS_EnumerateStub;
interface_object_class->resolve = JS_ResolveStub;
interface_object_class->convert = JS_ConvertStub;
+ interface_object_class->hasInstance = &HasInstance;
return interface_data;
}
@@ -276,14 +297,12 @@
};
void InitializePrototypeAndInterfaceObject(
- InterfaceData* interface_data, JSContext* context) {
+ InterfaceData* interface_data, JSContext* context,
+ JS::HandleObject global_object) {
DCHECK(!interface_data->prototype);
DCHECK(!interface_data->interface_object);
+ DCHECK(JS_IsGlobalObject(global_object));
- MozjsGlobalObjectProxy* global_object_proxy =
- static_cast<MozjsGlobalObjectProxy*>(JS_GetContextPrivate(context));
- JS::RootedObject global_object(context, global_object_proxy->global_object());
- DCHECK(global_object);
JS::RootedObject parent_prototype(
context, JS_GetObjectPrototype(context, global_object));
DCHECK(parent_prototype);
@@ -362,8 +381,11 @@
// static
JSObject* MozjsStringifierAttributeInterface::CreateProxy(
JSContext* context, const scoped_refptr<Wrappable>& wrappable) {
+ JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+ DCHECK(global_object);
+
InterfaceData* interface_data = GetInterfaceData(context);
- JS::RootedObject prototype(context, GetPrototype(context));
+ JS::RootedObject prototype(context, GetPrototype(context, global_object));
DCHECK(prototype);
JS::RootedObject new_object(context, JS_NewObjectWithGivenProto(
context, &interface_data->instance_class_definition, prototype, NULL));
@@ -371,34 +393,45 @@
JS::RootedObject proxy(context,
ProxyHandler::NewProxy(context, new_object, prototype, NULL,
proxy_handler.Pointer()));
- WrapperPrivate::AddPrivateData(proxy, wrappable);
+ WrapperPrivate::AddPrivateData(context, proxy, wrappable);
return proxy;
}
//static
const JSClass* MozjsStringifierAttributeInterface::PrototypeClass(
JSContext* context) {
- JS::RootedObject prototype(context, GetPrototype(context));
+ JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+ DCHECK(global_object);
+
+ JS::RootedObject prototype(context, GetPrototype(context, global_object));
JSClass* proto_class = JS_GetClass(*prototype.address());
return proto_class;
}
// static
-JSObject* MozjsStringifierAttributeInterface::GetPrototype(JSContext* context) {
+JSObject* MozjsStringifierAttributeInterface::GetPrototype(
+ JSContext* context, JS::HandleObject global_object) {
+ DCHECK(JS_IsGlobalObject(global_object));
+
InterfaceData* interface_data = GetInterfaceData(context);
if (!interface_data->prototype) {
// Create new prototype that has all the props and methods
- InitializePrototypeAndInterfaceObject(interface_data, context);
+ InitializePrototypeAndInterfaceObject(
+ interface_data, context, global_object);
}
DCHECK(interface_data->prototype);
return interface_data->prototype;
}
// static
-JSObject* MozjsStringifierAttributeInterface::GetInterfaceObject(JSContext* context) {
+JSObject* MozjsStringifierAttributeInterface::GetInterfaceObject(
+ JSContext* context, JS::HandleObject global_object) {
+ DCHECK(JS_IsGlobalObject(global_object));
+
InterfaceData* interface_data = GetInterfaceData(context);
if (!interface_data->interface_object) {
- InitializePrototypeAndInterfaceObject(interface_data, context);
+ InitializePrototypeAndInterfaceObject(
+ interface_data, context, global_object);
}
DCHECK(interface_data->interface_object);
return interface_data->interface_object;
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsStringifierAttributeInterface.h b/src/cobalt/bindings/generated/mozjs/testing/MozjsStringifierAttributeInterface.h
index 813ec74..fcf8292 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsStringifierAttributeInterface.h
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsStringifierAttributeInterface.h
@@ -41,8 +41,10 @@
static JSObject* CreateProxy(JSContext* context,
const scoped_refptr<script::Wrappable>& wrappable);
static const JSClass* PrototypeClass(JSContext* context);
- static JSObject* GetPrototype(JSContext* context);
- static JSObject* GetInterfaceObject(JSContext* context);
+ static JSObject* GetPrototype(JSContext* context,
+ JS::HandleObject global_object);
+ static JSObject* GetInterfaceObject(JSContext* context,
+ JS::HandleObject global_object);
};
} // namespace bindings
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsStringifierOperationInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsStringifierOperationInterface.cc
index 30a5d06..3a96a4b 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsStringifierOperationInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsStringifierOperationInterface.cc
@@ -114,6 +114,26 @@
static base::LazyInstance<MozjsStringifierOperationInterfaceHandler>
proxy_handler;
+JSBool HasInstance(JSContext *context, JS::HandleObject type,
+ JS::MutableHandleValue vp, JSBool *success) {
+ JS::RootedObject global_object(
+ context, JS_GetGlobalForObject(context, type));
+ DCHECK(global_object);
+
+ JS::RootedObject prototype(
+ context, MozjsStringifierOperationInterface::GetPrototype(context, global_object));
+
+ // |IsDelegate| walks the prototype chain of an object returning true if
+ // .prototype is found.
+ bool is_delegate;
+ if (!IsDelegate(context, prototype, vp, &is_delegate)) {
+ *success = false;
+ return false;
+ }
+
+ *success = is_delegate;
+ return true;
+}
InterfaceData* CreateCachedInterfaceData() {
InterfaceData* interface_data = new InterfaceData();
@@ -162,6 +182,7 @@
interface_object_class->enumerate = JS_EnumerateStub;
interface_object_class->resolve = JS_ResolveStub;
interface_object_class->convert = JS_ConvertStub;
+ interface_object_class->hasInstance = &HasInstance;
return interface_data;
}
@@ -267,14 +288,12 @@
};
void InitializePrototypeAndInterfaceObject(
- InterfaceData* interface_data, JSContext* context) {
+ InterfaceData* interface_data, JSContext* context,
+ JS::HandleObject global_object) {
DCHECK(!interface_data->prototype);
DCHECK(!interface_data->interface_object);
+ DCHECK(JS_IsGlobalObject(global_object));
- MozjsGlobalObjectProxy* global_object_proxy =
- static_cast<MozjsGlobalObjectProxy*>(JS_GetContextPrivate(context));
- JS::RootedObject global_object(context, global_object_proxy->global_object());
- DCHECK(global_object);
JS::RootedObject parent_prototype(
context, JS_GetObjectPrototype(context, global_object));
DCHECK(parent_prototype);
@@ -353,8 +372,11 @@
// static
JSObject* MozjsStringifierOperationInterface::CreateProxy(
JSContext* context, const scoped_refptr<Wrappable>& wrappable) {
+ JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+ DCHECK(global_object);
+
InterfaceData* interface_data = GetInterfaceData(context);
- JS::RootedObject prototype(context, GetPrototype(context));
+ JS::RootedObject prototype(context, GetPrototype(context, global_object));
DCHECK(prototype);
JS::RootedObject new_object(context, JS_NewObjectWithGivenProto(
context, &interface_data->instance_class_definition, prototype, NULL));
@@ -362,34 +384,45 @@
JS::RootedObject proxy(context,
ProxyHandler::NewProxy(context, new_object, prototype, NULL,
proxy_handler.Pointer()));
- WrapperPrivate::AddPrivateData(proxy, wrappable);
+ WrapperPrivate::AddPrivateData(context, proxy, wrappable);
return proxy;
}
//static
const JSClass* MozjsStringifierOperationInterface::PrototypeClass(
JSContext* context) {
- JS::RootedObject prototype(context, GetPrototype(context));
+ JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+ DCHECK(global_object);
+
+ JS::RootedObject prototype(context, GetPrototype(context, global_object));
JSClass* proto_class = JS_GetClass(*prototype.address());
return proto_class;
}
// static
-JSObject* MozjsStringifierOperationInterface::GetPrototype(JSContext* context) {
+JSObject* MozjsStringifierOperationInterface::GetPrototype(
+ JSContext* context, JS::HandleObject global_object) {
+ DCHECK(JS_IsGlobalObject(global_object));
+
InterfaceData* interface_data = GetInterfaceData(context);
if (!interface_data->prototype) {
// Create new prototype that has all the props and methods
- InitializePrototypeAndInterfaceObject(interface_data, context);
+ InitializePrototypeAndInterfaceObject(
+ interface_data, context, global_object);
}
DCHECK(interface_data->prototype);
return interface_data->prototype;
}
// static
-JSObject* MozjsStringifierOperationInterface::GetInterfaceObject(JSContext* context) {
+JSObject* MozjsStringifierOperationInterface::GetInterfaceObject(
+ JSContext* context, JS::HandleObject global_object) {
+ DCHECK(JS_IsGlobalObject(global_object));
+
InterfaceData* interface_data = GetInterfaceData(context);
if (!interface_data->interface_object) {
- InitializePrototypeAndInterfaceObject(interface_data, context);
+ InitializePrototypeAndInterfaceObject(
+ interface_data, context, global_object);
}
DCHECK(interface_data->interface_object);
return interface_data->interface_object;
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsStringifierOperationInterface.h b/src/cobalt/bindings/generated/mozjs/testing/MozjsStringifierOperationInterface.h
index 135e07a..a5f76d1 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsStringifierOperationInterface.h
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsStringifierOperationInterface.h
@@ -41,8 +41,10 @@
static JSObject* CreateProxy(JSContext* context,
const scoped_refptr<script::Wrappable>& wrappable);
static const JSClass* PrototypeClass(JSContext* context);
- static JSObject* GetPrototype(JSContext* context);
- static JSObject* GetInterfaceObject(JSContext* context);
+ static JSObject* GetPrototype(JSContext* context,
+ JS::HandleObject global_object);
+ static JSObject* GetInterfaceObject(JSContext* context,
+ JS::HandleObject global_object);
};
} // namespace bindings
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsTargetInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsTargetInterface.cc
index b7d73d0..49786d1 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsTargetInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsTargetInterface.cc
@@ -114,6 +114,26 @@
static base::LazyInstance<MozjsTargetInterfaceHandler>
proxy_handler;
+JSBool HasInstance(JSContext *context, JS::HandleObject type,
+ JS::MutableHandleValue vp, JSBool *success) {
+ JS::RootedObject global_object(
+ context, JS_GetGlobalForObject(context, type));
+ DCHECK(global_object);
+
+ JS::RootedObject prototype(
+ context, MozjsTargetInterface::GetPrototype(context, global_object));
+
+ // |IsDelegate| walks the prototype chain of an object returning true if
+ // .prototype is found.
+ bool is_delegate;
+ if (!IsDelegate(context, prototype, vp, &is_delegate)) {
+ *success = false;
+ return false;
+ }
+
+ *success = is_delegate;
+ return true;
+}
InterfaceData* CreateCachedInterfaceData() {
InterfaceData* interface_data = new InterfaceData();
@@ -162,6 +182,7 @@
interface_object_class->enumerate = JS_EnumerateStub;
interface_object_class->resolve = JS_ResolveStub;
interface_object_class->convert = JS_ConvertStub;
+ interface_object_class->hasInstance = &HasInstance;
return interface_data;
}
@@ -257,14 +278,12 @@
};
void InitializePrototypeAndInterfaceObject(
- InterfaceData* interface_data, JSContext* context) {
+ InterfaceData* interface_data, JSContext* context,
+ JS::HandleObject global_object) {
DCHECK(!interface_data->prototype);
DCHECK(!interface_data->interface_object);
+ DCHECK(JS_IsGlobalObject(global_object));
- MozjsGlobalObjectProxy* global_object_proxy =
- static_cast<MozjsGlobalObjectProxy*>(JS_GetContextPrivate(context));
- JS::RootedObject global_object(context, global_object_proxy->global_object());
- DCHECK(global_object);
JS::RootedObject parent_prototype(
context, JS_GetObjectPrototype(context, global_object));
DCHECK(parent_prototype);
@@ -343,8 +362,11 @@
// static
JSObject* MozjsTargetInterface::CreateProxy(
JSContext* context, const scoped_refptr<Wrappable>& wrappable) {
+ JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+ DCHECK(global_object);
+
InterfaceData* interface_data = GetInterfaceData(context);
- JS::RootedObject prototype(context, GetPrototype(context));
+ JS::RootedObject prototype(context, GetPrototype(context, global_object));
DCHECK(prototype);
JS::RootedObject new_object(context, JS_NewObjectWithGivenProto(
context, &interface_data->instance_class_definition, prototype, NULL));
@@ -352,34 +374,45 @@
JS::RootedObject proxy(context,
ProxyHandler::NewProxy(context, new_object, prototype, NULL,
proxy_handler.Pointer()));
- WrapperPrivate::AddPrivateData(proxy, wrappable);
+ WrapperPrivate::AddPrivateData(context, proxy, wrappable);
return proxy;
}
//static
const JSClass* MozjsTargetInterface::PrototypeClass(
JSContext* context) {
- JS::RootedObject prototype(context, GetPrototype(context));
+ JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+ DCHECK(global_object);
+
+ JS::RootedObject prototype(context, GetPrototype(context, global_object));
JSClass* proto_class = JS_GetClass(*prototype.address());
return proto_class;
}
// static
-JSObject* MozjsTargetInterface::GetPrototype(JSContext* context) {
+JSObject* MozjsTargetInterface::GetPrototype(
+ JSContext* context, JS::HandleObject global_object) {
+ DCHECK(JS_IsGlobalObject(global_object));
+
InterfaceData* interface_data = GetInterfaceData(context);
if (!interface_data->prototype) {
// Create new prototype that has all the props and methods
- InitializePrototypeAndInterfaceObject(interface_data, context);
+ InitializePrototypeAndInterfaceObject(
+ interface_data, context, global_object);
}
DCHECK(interface_data->prototype);
return interface_data->prototype;
}
// static
-JSObject* MozjsTargetInterface::GetInterfaceObject(JSContext* context) {
+JSObject* MozjsTargetInterface::GetInterfaceObject(
+ JSContext* context, JS::HandleObject global_object) {
+ DCHECK(JS_IsGlobalObject(global_object));
+
InterfaceData* interface_data = GetInterfaceData(context);
if (!interface_data->interface_object) {
- InitializePrototypeAndInterfaceObject(interface_data, context);
+ InitializePrototypeAndInterfaceObject(
+ interface_data, context, global_object);
}
DCHECK(interface_data->interface_object);
return interface_data->interface_object;
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsTargetInterface.h b/src/cobalt/bindings/generated/mozjs/testing/MozjsTargetInterface.h
index 71f1e20..34254e0 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsTargetInterface.h
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsTargetInterface.h
@@ -41,8 +41,10 @@
static JSObject* CreateProxy(JSContext* context,
const scoped_refptr<script::Wrappable>& wrappable);
static const JSClass* PrototypeClass(JSContext* context);
- static JSObject* GetPrototype(JSContext* context);
- static JSObject* GetInterfaceObject(JSContext* context);
+ static JSObject* GetPrototype(JSContext* context,
+ JS::HandleObject global_object);
+ static JSObject* GetInterfaceObject(JSContext* context,
+ JS::HandleObject global_object);
};
} // namespace bindings
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsUnionTypesInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsUnionTypesInterface.cc
index 8d181ac..bc19f25 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsUnionTypesInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsUnionTypesInterface.cc
@@ -122,6 +122,26 @@
static base::LazyInstance<MozjsUnionTypesInterfaceHandler>
proxy_handler;
+JSBool HasInstance(JSContext *context, JS::HandleObject type,
+ JS::MutableHandleValue vp, JSBool *success) {
+ JS::RootedObject global_object(
+ context, JS_GetGlobalForObject(context, type));
+ DCHECK(global_object);
+
+ JS::RootedObject prototype(
+ context, MozjsUnionTypesInterface::GetPrototype(context, global_object));
+
+ // |IsDelegate| walks the prototype chain of an object returning true if
+ // .prototype is found.
+ bool is_delegate;
+ if (!IsDelegate(context, prototype, vp, &is_delegate)) {
+ *success = false;
+ return false;
+ }
+
+ *success = is_delegate;
+ return true;
+}
InterfaceData* CreateCachedInterfaceData() {
InterfaceData* interface_data = new InterfaceData();
@@ -170,6 +190,7 @@
interface_object_class->enumerate = JS_EnumerateStub;
interface_object_class->resolve = JS_ResolveStub;
interface_object_class->convert = JS_ConvertStub;
+ interface_object_class->hasInstance = &HasInstance;
return interface_data;
}
@@ -395,14 +416,12 @@
};
void InitializePrototypeAndInterfaceObject(
- InterfaceData* interface_data, JSContext* context) {
+ InterfaceData* interface_data, JSContext* context,
+ JS::HandleObject global_object) {
DCHECK(!interface_data->prototype);
DCHECK(!interface_data->interface_object);
+ DCHECK(JS_IsGlobalObject(global_object));
- MozjsGlobalObjectProxy* global_object_proxy =
- static_cast<MozjsGlobalObjectProxy*>(JS_GetContextPrivate(context));
- JS::RootedObject global_object(context, global_object_proxy->global_object());
- DCHECK(global_object);
JS::RootedObject parent_prototype(
context, JS_GetObjectPrototype(context, global_object));
DCHECK(parent_prototype);
@@ -481,8 +500,11 @@
// static
JSObject* MozjsUnionTypesInterface::CreateProxy(
JSContext* context, const scoped_refptr<Wrappable>& wrappable) {
+ JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+ DCHECK(global_object);
+
InterfaceData* interface_data = GetInterfaceData(context);
- JS::RootedObject prototype(context, GetPrototype(context));
+ JS::RootedObject prototype(context, GetPrototype(context, global_object));
DCHECK(prototype);
JS::RootedObject new_object(context, JS_NewObjectWithGivenProto(
context, &interface_data->instance_class_definition, prototype, NULL));
@@ -490,34 +512,45 @@
JS::RootedObject proxy(context,
ProxyHandler::NewProxy(context, new_object, prototype, NULL,
proxy_handler.Pointer()));
- WrapperPrivate::AddPrivateData(proxy, wrappable);
+ WrapperPrivate::AddPrivateData(context, proxy, wrappable);
return proxy;
}
//static
const JSClass* MozjsUnionTypesInterface::PrototypeClass(
JSContext* context) {
- JS::RootedObject prototype(context, GetPrototype(context));
+ JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+ DCHECK(global_object);
+
+ JS::RootedObject prototype(context, GetPrototype(context, global_object));
JSClass* proto_class = JS_GetClass(*prototype.address());
return proto_class;
}
// static
-JSObject* MozjsUnionTypesInterface::GetPrototype(JSContext* context) {
+JSObject* MozjsUnionTypesInterface::GetPrototype(
+ JSContext* context, JS::HandleObject global_object) {
+ DCHECK(JS_IsGlobalObject(global_object));
+
InterfaceData* interface_data = GetInterfaceData(context);
if (!interface_data->prototype) {
// Create new prototype that has all the props and methods
- InitializePrototypeAndInterfaceObject(interface_data, context);
+ InitializePrototypeAndInterfaceObject(
+ interface_data, context, global_object);
}
DCHECK(interface_data->prototype);
return interface_data->prototype;
}
// static
-JSObject* MozjsUnionTypesInterface::GetInterfaceObject(JSContext* context) {
+JSObject* MozjsUnionTypesInterface::GetInterfaceObject(
+ JSContext* context, JS::HandleObject global_object) {
+ DCHECK(JS_IsGlobalObject(global_object));
+
InterfaceData* interface_data = GetInterfaceData(context);
if (!interface_data->interface_object) {
- InitializePrototypeAndInterfaceObject(interface_data, context);
+ InitializePrototypeAndInterfaceObject(
+ interface_data, context, global_object);
}
DCHECK(interface_data->interface_object);
return interface_data->interface_object;
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsUnionTypesInterface.h b/src/cobalt/bindings/generated/mozjs/testing/MozjsUnionTypesInterface.h
index eba6b2f..7de2382 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsUnionTypesInterface.h
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsUnionTypesInterface.h
@@ -41,8 +41,10 @@
static JSObject* CreateProxy(JSContext* context,
const scoped_refptr<script::Wrappable>& wrappable);
static const JSClass* PrototypeClass(JSContext* context);
- static JSObject* GetPrototype(JSContext* context);
- static JSObject* GetInterfaceObject(JSContext* context);
+ static JSObject* GetPrototype(JSContext* context,
+ JS::HandleObject global_object);
+ static JSObject* GetInterfaceObject(JSContext* context,
+ JS::HandleObject global_object);
};
} // namespace bindings
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsWindow.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsWindow.cc
index b626b88..f52bcf2 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsWindow.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsWindow.cc
@@ -298,6 +298,26 @@
static base::LazyInstance<MozjsWindowHandler>
proxy_handler;
+JSBool HasInstance(JSContext *context, JS::HandleObject type,
+ JS::MutableHandleValue vp, JSBool *success) {
+ JS::RootedObject global_object(
+ context, JS_GetGlobalForObject(context, type));
+ DCHECK(global_object);
+
+ JS::RootedObject prototype(
+ context, MozjsWindow::GetPrototype(context, global_object));
+
+ // |IsDelegate| walks the prototype chain of an object returning true if
+ // .prototype is found.
+ bool is_delegate;
+ if (!IsDelegate(context, prototype, vp, &is_delegate)) {
+ *success = false;
+ return false;
+ }
+
+ *success = is_delegate;
+ return true;
+}
InterfaceData* CreateCachedInterfaceData() {
InterfaceData* interface_data = new InterfaceData();
@@ -346,6 +366,7 @@
interface_object_class->enumerate = JS_EnumerateStub;
interface_object_class->resolve = JS_ResolveStub;
interface_object_class->convert = JS_ConvertStub;
+ interface_object_class->hasInstance = &HasInstance;
return interface_data;
}
@@ -393,6 +414,64 @@
return !exception_state.is_exception_set();
}
+JSBool get_window(
+ JSContext* context, JS::HandleObject object, JS::HandleId id,
+ JS::MutableHandleValue vp) {
+ MozjsExceptionState exception_state(context);
+ JS::RootedValue result_value(context);
+
+ WrapperPrivate* wrapper_private =
+ WrapperPrivate::GetFromObject(context, object);
+ Window* impl =
+ wrapper_private->wrappable<Window>().get();
+
+ if (!exception_state.is_exception_set()) {
+ ToJSValue(context,
+ impl->window(),
+ &result_value);
+ }
+ if (!exception_state.is_exception_set()) {
+ vp.set(result_value);
+ }
+ return !exception_state.is_exception_set();
+}
+
+JSBool fcn_getStackTrace(
+ JSContext* context, uint32_t argc, JS::Value *vp) {
+ JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+ // Compute the 'this' value.
+ JS::RootedValue this_value(context, JS_ComputeThis(context, vp));
+ // 'this' should be an object.
+ JS::RootedObject object(context);
+ if (JS_TypeOfValue(context, this_value) != JSTYPE_OBJECT) {
+ NOTREACHED();
+ return false;
+ }
+ if (!JS_ValueToObject(context, this_value, object.address())) {
+ NOTREACHED();
+ return false;
+ }
+ MozjsExceptionState exception_state(context);
+ JS::RootedValue result_value(context);
+
+ WrapperPrivate* wrapper_private =
+ WrapperPrivate::GetFromObject(context, object);
+ Window* impl =
+ wrapper_private->wrappable<Window>().get();
+ MozjsGlobalObjectProxy* global_object_proxy =
+ static_cast<MozjsGlobalObjectProxy*>(JS_GetContextPrivate(context));
+
+ if (!exception_state.is_exception_set()) {
+ ToJSValue(context,
+ impl->GetStackTrace(global_object_proxy->GetStackTrace()),
+ &result_value);
+ }
+ if (!exception_state.is_exception_set()) {
+ args.rval().set(result_value);
+ }
+ return !exception_state.is_exception_set();
+}
+
JSBool fcn_windowOperation(
JSContext* context, uint32_t argc, JS::Value *vp) {
JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
@@ -429,11 +508,24 @@
JSOP_WRAPPER(&get_windowProperty),
JSOP_WRAPPER(&set_windowProperty),
},
+ { // Readonly attribute
+ "window", 0,
+ JSPROP_SHARED | JSPROP_ENUMERATE | JSPROP_READONLY,
+ JSOP_WRAPPER(&get_window),
+ JSOP_NULLWRAPPER,
+ },
JS_PS_END
};
const JSFunctionSpec prototype_functions[] = {
{
+ "getStackTrace",
+ JSOP_WRAPPER(&fcn_getStackTrace),
+ 0,
+ JSPROP_ENUMERATE,
+ NULL,
+ },
+ {
"windowOperation",
JSOP_WRAPPER(&fcn_windowOperation),
0,
@@ -456,16 +548,14 @@
};
void InitializePrototypeAndInterfaceObject(
- InterfaceData* interface_data, JSContext* context) {
+ InterfaceData* interface_data, JSContext* context,
+ JS::HandleObject global_object) {
DCHECK(!interface_data->prototype);
DCHECK(!interface_data->interface_object);
+ DCHECK(JS_IsGlobalObject(global_object));
- MozjsGlobalObjectProxy* global_object_proxy =
- static_cast<MozjsGlobalObjectProxy*>(JS_GetContextPrivate(context));
- JS::RootedObject global_object(context, global_object_proxy->global_object());
- DCHECK(global_object);
JS::RootedObject parent_prototype(
- context, bindings::testing::MozjsGlobalInterfaceParent::GetPrototype(context));
+ context, bindings::testing::MozjsGlobalInterfaceParent::GetPrototype(context, global_object));
DCHECK(parent_prototype);
// Create the Prototype object.
@@ -556,13 +646,8 @@
JS::RootedObject parent_prototype(
context, JS_GetObjectPrototype(context, global_object));
- // Set the global object pointer, so we can access the standard classes such
- // as the base Object prototype when looking up our prototype.
- MozjsGlobalObjectProxy* global_object_proxy =
- static_cast<MozjsGlobalObjectProxy*>(JS_GetContextPrivate(context));
- global_object_proxy->SetGlobalObject(global_object);
-
- JS::RootedObject prototype(context, MozjsWindow::GetPrototype(context));
+ JS::RootedObject prototype(
+ context, MozjsWindow::GetPrototype(context, global_object));
DCHECK(prototype);
JS_SetPrototype(context, global_object, prototype);
@@ -573,34 +658,51 @@
JS::RootedObject proxy(context,
ProxyHandler::NewProxy(context, global_object, prototype, NULL,
proxy_handler.Pointer()));
- WrapperPrivate::AddPrivateData(proxy, wrappable);
+ WrapperPrivate::AddPrivateData(context, proxy, wrappable);
+
+ // Set the global object proxy pointer, so we can access the standard classes
+ // such as the base Object prototype when looking up our prototype.
+ MozjsGlobalObjectProxy* global_object_proxy =
+ static_cast<MozjsGlobalObjectProxy*>(JS_GetContextPrivate(context));
+ global_object_proxy->SetGlobalObjectProxyAndWrapper(proxy, wrappable);
return proxy;
}
//static
const JSClass* MozjsWindow::PrototypeClass(
JSContext* context) {
- JS::RootedObject prototype(context, GetPrototype(context));
+ JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+ DCHECK(global_object);
+
+ JS::RootedObject prototype(context, GetPrototype(context, global_object));
JSClass* proto_class = JS_GetClass(*prototype.address());
return proto_class;
}
// static
-JSObject* MozjsWindow::GetPrototype(JSContext* context) {
+JSObject* MozjsWindow::GetPrototype(
+ JSContext* context, JS::HandleObject global_object) {
+ DCHECK(JS_IsGlobalObject(global_object));
+
InterfaceData* interface_data = GetInterfaceData(context);
if (!interface_data->prototype) {
// Create new prototype that has all the props and methods
- InitializePrototypeAndInterfaceObject(interface_data, context);
+ InitializePrototypeAndInterfaceObject(
+ interface_data, context, global_object);
}
DCHECK(interface_data->prototype);
return interface_data->prototype;
}
// static
-JSObject* MozjsWindow::GetInterfaceObject(JSContext* context) {
+JSObject* MozjsWindow::GetInterfaceObject(
+ JSContext* context, JS::HandleObject global_object) {
+ DCHECK(JS_IsGlobalObject(global_object));
+
InterfaceData* interface_data = GetInterfaceData(context);
if (!interface_data->interface_object) {
- InitializePrototypeAndInterfaceObject(interface_data, context);
+ InitializePrototypeAndInterfaceObject(
+ interface_data, context, global_object);
}
DCHECK(interface_data->interface_object);
return interface_data->interface_object;
@@ -629,7 +731,8 @@
context, global_interface);
mozjs_global_object_proxy->SetEnvironmentSettings(environment_settings);
- WrapperFactory* wrapper_factory = mozjs_global_object_proxy->wrapper_factory();
+ WrapperFactory* wrapper_factory =
+ mozjs_global_object_proxy->wrapper_factory();
wrapper_factory->RegisterWrappableType(
AnonymousIndexedGetterInterface::AnonymousIndexedGetterInterfaceWrappableType(),
base::Bind(MozjsAnonymousIndexedGetterInterface::CreateProxy),
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsWindow.h b/src/cobalt/bindings/generated/mozjs/testing/MozjsWindow.h
index c7e508c..50db9dd 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsWindow.h
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsWindow.h
@@ -42,8 +42,10 @@
static JSObject* CreateProxy(JSContext* context,
const scoped_refptr<script::Wrappable>& wrappable);
static const JSClass* PrototypeClass(JSContext* context);
- static JSObject* GetPrototype(JSContext* context);
- static JSObject* GetInterfaceObject(JSContext* context);
+ static JSObject* GetPrototype(JSContext* context,
+ JS::HandleObject global_object);
+ static JSObject* GetInterfaceObject(JSContext* context,
+ JS::HandleObject global_object);
};
} // namespace bindings
diff --git a/src/cobalt/bindings/mozjs/templates/interface.cc.template b/src/cobalt/bindings/mozjs/templates/interface.cc.template
index ad65ba4..16134d5 100644
--- a/src/cobalt/bindings/mozjs/templates/interface.cc.template
+++ b/src/cobalt/bindings/mozjs/templates/interface.cc.template
@@ -41,6 +41,9 @@
#include "cobalt/script/mozjs/wrapper_private.h"
#include "cobalt/script/property_enumerator.h"
#include "third_party/mozjs/js/src/jsapi.h"
+{% if is_exception_interface %}
+#include "third_party/mozjs/js/src/jsexn.h"
+{% endif %}
#include "third_party/mozjs/js/src/jsfriendapi.h"
{% endblock includes %}
{% block using_directives %}
@@ -317,6 +320,26 @@
}
{% endfor %}
+JSBool HasInstance(JSContext *context, JS::HandleObject type,
+ JS::MutableHandleValue vp, JSBool *success) {
+ JS::RootedObject global_object(
+ context, JS_GetGlobalForObject(context, type));
+ DCHECK(global_object);
+
+ JS::RootedObject prototype(
+ context, {{binding_class}}::GetPrototype(context, global_object));
+
+ // |IsDelegate| walks the prototype chain of an object returning true if
+ // .prototype is found.
+ bool is_delegate;
+ if (!IsDelegate(context, prototype, vp, &is_delegate)) {
+ *success = false;
+ return false;
+ }
+
+ *success = is_delegate;
+ return true;
+}
InterfaceData* CreateCachedInterfaceData() {
InterfaceData* interface_data = new InterfaceData();
@@ -366,6 +389,7 @@
interface_object_class->enumerate = JS_EnumerateStub;
interface_object_class->resolve = JS_ResolveStub;
interface_object_class->convert = JS_ConvertStub;
+ interface_object_class->hasInstance = &HasInstance;
{% if constructor %}
interface_object_class->construct = Constructor;
{% endif %}
@@ -380,8 +404,13 @@
JSBool get_{{attribute.idl_name}}(
JSContext* context, JS::HandleObject object, JS::HandleId id,
JS::MutableHandleValue vp) {
+ JS::RootedObject global_object(
+ context, JS_GetGlobalForObject(context, object));
+ DCHECK(global_object);
+
JS::RootedObject interface_object(context,
- Mozjs{{attribute.interface_name}}::GetInterfaceObject(context));
+ Mozjs{{attribute.interface_name}}::GetInterfaceObject(
+ context, global_object));
vp.set(JS::ObjectValue(*interface_object));
return true;
}
@@ -626,27 +655,34 @@
};
void InitializePrototypeAndInterfaceObject(
- InterfaceData* interface_data, JSContext* context) {
+ InterfaceData* interface_data, JSContext* context,
+ JS::HandleObject global_object) {
DCHECK(!interface_data->prototype);
DCHECK(!interface_data->interface_object);
+ DCHECK(JS_IsGlobalObject(global_object));
- MozjsGlobalObjectProxy* global_object_proxy =
- static_cast<MozjsGlobalObjectProxy*>(JS_GetContextPrivate(context));
- JS::RootedObject global_object(context, global_object_proxy->global_object());
- DCHECK(global_object);
{% if parent_interface %}
JS::RootedObject parent_prototype(
- context, {{parent_interface}}::GetPrototype(context));
+ context, {{parent_interface}}::GetPrototype(context, global_object));
{% else %}
JS::RootedObject parent_prototype(
context, JS_GetObjectPrototype(context, global_object));
{% endif %}
DCHECK(parent_prototype);
+{% if is_exception_interface %}
+ JS::RootedObject prototype(context);
+ // Get Error prototype.
+ bool success_check = js_GetClassPrototype(
+ context, GetExceptionProtoKey(JSEXN_ERR), &prototype);
+ DCHECK(success_check);
+ interface_data->prototype = prototype;
+{% else %}
// Create the Prototype object.
interface_data->prototype = JS_NewObjectWithGivenProto(
context, &interface_data->prototype_class_definition, parent_prototype,
NULL);
+{% endif %}
bool success = JS_DefineProperties(
context, interface_data->prototype, prototype_properties);
DCHECK(success);
@@ -746,13 +782,8 @@
JS::RootedObject parent_prototype(
context, JS_GetObjectPrototype(context, global_object));
- // Set the global object pointer, so we can access the standard classes such
- // as the base Object prototype when looking up our prototype.
- MozjsGlobalObjectProxy* global_object_proxy =
- static_cast<MozjsGlobalObjectProxy*>(JS_GetContextPrivate(context));
- global_object_proxy->SetGlobalObject(global_object);
-
- JS::RootedObject prototype(context, {{binding_class}}::GetPrototype(context));
+ JS::RootedObject prototype(
+ context, {{binding_class}}::GetPrototype(context, global_object));
DCHECK(prototype);
JS_SetPrototype(context, global_object, prototype);
@@ -763,7 +794,13 @@
JS::RootedObject proxy(context,
ProxyHandler::NewProxy(context, global_object, prototype, NULL,
proxy_handler.Pointer()));
- WrapperPrivate::AddPrivateData(proxy, wrappable);
+ WrapperPrivate::AddPrivateData(context, proxy, wrappable);
+
+ // Set the global object proxy pointer, so we can access the standard classes
+ // such as the base Object prototype when looking up our prototype.
+ MozjsGlobalObjectProxy* global_object_proxy =
+ static_cast<MozjsGlobalObjectProxy*>(JS_GetContextPrivate(context));
+ global_object_proxy->SetGlobalObjectProxyAndWrapper(proxy, wrappable);
return proxy;
}
@@ -771,8 +808,11 @@
// static
JSObject* {{binding_class}}::CreateProxy(
JSContext* context, const scoped_refptr<Wrappable>& wrappable) {
+ JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+ DCHECK(global_object);
+
InterfaceData* interface_data = GetInterfaceData(context);
- JS::RootedObject prototype(context, GetPrototype(context));
+ JS::RootedObject prototype(context, GetPrototype(context, global_object));
DCHECK(prototype);
JS::RootedObject new_object(context, JS_NewObjectWithGivenProto(
context, &interface_data->instance_class_definition, prototype, NULL));
@@ -780,7 +820,7 @@
JS::RootedObject proxy(context,
ProxyHandler::NewProxy(context, new_object, prototype, NULL,
proxy_handler.Pointer()));
- WrapperPrivate::AddPrivateData(proxy, wrappable);
+ WrapperPrivate::AddPrivateData(context, proxy, wrappable);
return proxy;
}
@@ -788,17 +828,24 @@
//static
const JSClass* {{binding_class}}::PrototypeClass(
JSContext* context) {
- JS::RootedObject prototype(context, GetPrototype(context));
+ JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+ DCHECK(global_object);
+
+ JS::RootedObject prototype(context, GetPrototype(context, global_object));
JSClass* proto_class = JS_GetClass(*prototype.address());
return proto_class;
}
// static
-JSObject* {{binding_class}}::GetPrototype(JSContext* context) {
+JSObject* {{binding_class}}::GetPrototype(
+ JSContext* context, JS::HandleObject global_object) {
+ DCHECK(JS_IsGlobalObject(global_object));
+
InterfaceData* interface_data = GetInterfaceData(context);
if (!interface_data->prototype) {
// Create new prototype that has all the props and methods
- InitializePrototypeAndInterfaceObject(interface_data, context);
+ InitializePrototypeAndInterfaceObject(
+ interface_data, context, global_object);
}
DCHECK(interface_data->prototype);
return interface_data->prototype;
@@ -806,10 +853,14 @@
{% if has_interface_object %}
// static
-JSObject* {{binding_class}}::GetInterfaceObject(JSContext* context) {
+JSObject* {{binding_class}}::GetInterfaceObject(
+ JSContext* context, JS::HandleObject global_object) {
+ DCHECK(JS_IsGlobalObject(global_object));
+
InterfaceData* interface_data = GetInterfaceData(context);
if (!interface_data->interface_object) {
- InitializePrototypeAndInterfaceObject(interface_data, context);
+ InitializePrototypeAndInterfaceObject(
+ interface_data, context, global_object);
}
DCHECK(interface_data->interface_object);
return interface_data->interface_object;
@@ -847,7 +898,8 @@
context, global_interface);
mozjs_global_object_proxy->SetEnvironmentSettings(environment_settings);
- WrapperFactory* wrapper_factory = mozjs_global_object_proxy->wrapper_factory();
+ WrapperFactory* wrapper_factory =
+ mozjs_global_object_proxy->wrapper_factory();
{% for interface in all_interfaces %}
{% if interface.conditional %}
#if defined({{interface.conditional}})
diff --git a/src/cobalt/bindings/mozjs/templates/interface.h.template b/src/cobalt/bindings/mozjs/templates/interface.h.template
index f7ca8b6..fbef85c 100644
--- a/src/cobalt/bindings/mozjs/templates/interface.h.template
+++ b/src/cobalt/bindings/mozjs/templates/interface.h.template
@@ -24,9 +24,11 @@
static JSObject* CreateProxy(JSContext* context,
const scoped_refptr<script::Wrappable>& wrappable);
static const JSClass* PrototypeClass(JSContext* context);
- static JSObject* GetPrototype(JSContext* context);
+ static JSObject* GetPrototype(JSContext* context,
+ JS::HandleObject global_object);
{% if has_interface_object %}
- static JSObject* GetInterfaceObject(JSContext* context);
+ static JSObject* GetInterfaceObject(JSContext* context,
+ JS::HandleObject global_object);
{% endif %}
};
{% endblock implementation %}
diff --git a/src/cobalt/bindings/mozjs/templates/macros.cc.template b/src/cobalt/bindings/mozjs/templates/macros.cc.template
index 36770e2..dd3bdca 100644
--- a/src/cobalt/bindings/mozjs/templates/macros.cc.template
+++ b/src/cobalt/bindings/mozjs/templates/macros.cc.template
@@ -336,6 +336,12 @@
constructor.call_with) }}
scoped_refptr<{{impl_class}}> new_object =
new {{impl_class}}({{arguments_list|join(', ')}});
+{% if constructor.raises_exception %}
+ // In case that an exception is thrown from constructor.
+ if (exception_state.is_exception_set()) {
+ return false;
+ }
+{% endif %}
JS::RootedValue result_value(context);
ToJSValue(context, new_object, &result_value);
DCHECK(result_value.isObject());
diff --git a/src/cobalt/bindings/testing/Window.idl b/src/cobalt/bindings/testing/Window.idl
index 9967ccf..161266f 100644
--- a/src/cobalt/bindings/testing/Window.idl
+++ b/src/cobalt/bindings/testing/Window.idl
@@ -17,4 +17,6 @@
interface Window : GlobalInterfaceParent {
void windowOperation();
attribute DOMString windowProperty;
+ readonly attribute Window window;
+ [CallWith=StackTrace] DOMString getStackTrace();
};
diff --git a/src/cobalt/bindings/testing/exceptions_bindings_test.cc b/src/cobalt/bindings/testing/exceptions_bindings_test.cc
index 0010125..13d6d0e 100644
--- a/src/cobalt/bindings/testing/exceptions_bindings_test.cc
+++ b/src/cobalt/bindings/testing/exceptions_bindings_test.cc
@@ -24,7 +24,7 @@
using ::testing::InSequence;
using ::testing::Invoke;
using ::testing::Return;
-using ::testing::StrictMock;
+using ::testing::NiceMock;
using ::testing::WithArg;
#define EXPECT_SUBSTRING(needle, haystack) \
@@ -54,8 +54,7 @@
public:
explicit ExceptionObjectSetter(
const scoped_refptr<ExceptionObjectInterface>& exception)
- : exception_object_(
- make_scoped_refptr<script::ScriptException>(exception.get())) {}
+ : exception_object_(exception) {}
void FireException(script::ExceptionState* exception) {
exception->SetException(exception_object_);
}
@@ -117,13 +116,12 @@
TEST_F(ExceptionsBindingsTest, ThrowExceptionObject) {
scoped_refptr<ExceptionObjectInterface> exception_object =
- make_scoped_refptr(new StrictMock<ExceptionObjectInterface>());
+ make_scoped_refptr(new NiceMock<ExceptionObjectInterface>());
ExceptionObjectSetter exception_setter(exception_object);
InSequence in_sequence_dummy;
EXPECT_CALL(test_mock(), FunctionThrowsException(_)).WillOnce(
Invoke(&exception_setter, &ExceptionObjectSetter::FireException));
- EXPECT_CALL(*exception_object, message()).WillOnce(Return("the message"));
EXPECT_TRUE(EvaluateScript(
"var error = null;"
"try { test.functionThrowsException(); }"
diff --git a/src/cobalt/bindings/testing/global_interface_bindings_test.cc b/src/cobalt/bindings/testing/global_interface_bindings_test.cc
index 175426e..5f8b90c 100644
--- a/src/cobalt/bindings/testing/global_interface_bindings_test.cc
+++ b/src/cobalt/bindings/testing/global_interface_bindings_test.cc
@@ -37,6 +37,10 @@
};
} // namespace
+TEST_F(GlobalInterfaceBindingsTest, GlobalWindowIsThis) {
+ EXPECT_TRUE(EvaluateScript("window === this;", NULL));
+}
+
TEST_F(GlobalInterfaceBindingsTest, GlobalOperation) {
EXPECT_CALL(test_mock(), WindowOperation());
EXPECT_TRUE(EvaluateScript("windowOperation();", NULL));
diff --git a/src/cobalt/bindings/testing/stack_trace_test.cc b/src/cobalt/bindings/testing/stack_trace_test.cc
new file mode 100644
index 0000000..c9e39a8
--- /dev/null
+++ b/src/cobalt/bindings/testing/stack_trace_test.cc
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2016 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 "cobalt/bindings/testing/bindings_test_base.h"
+
+namespace cobalt {
+namespace bindings {
+namespace testing {
+
+namespace {
+class StackTraceTest : public BindingsTestBase {};
+} // namespace
+
+TEST_F(StackTraceTest, GetStackTrace) {
+ std::string result;
+
+ // We expect the to be in bar (line 2), called from foo (line 6),
+ // called from foo (line 8) 4 times, called outside of a function (line
+ // 11).
+ std::string script =
+ "function bar() {\n"
+ "return getStackTrace();\n"
+ "}\n"
+ "function foo(depth) {\n"
+ " if (depth <= 0) {\n"
+ " return bar();\n"
+ " } else {\n"
+ " return foo(depth - 1);\n"
+ " }\n"
+ "}\n"
+ "foo(4)";
+ EXPECT_TRUE(EvaluateScript(script, &result));
+
+ // Expect that bar is on top.
+ std::string match_line = "bar @ [object BindingsTestBase]:2\n";
+ size_t position = result.find(match_line);
+ EXPECT_TRUE(position != std::string::npos);
+ // Expect a foo at line 6.
+ match_line = "foo @ [object BindingsTestBase]:6\n";
+ position = result.find(match_line, ++position);
+ EXPECT_TRUE(position != std::string::npos);
+ // Expect 4 subsequent foos at line 8.
+ match_line = "foo @ [object BindingsTestBase]:8\n";
+ for (int i = 0; i < 4; ++i) {
+ position = result.find(match_line, ++position);
+ EXPECT_TRUE(position != std::string::npos);
+ }
+ // Expect global code at line 11.
+ match_line = "global code @ [object BindingsTestBase]:11";
+ position = result.find(match_line, ++position);
+ EXPECT_TRUE(position != std::string::npos);
+}
+
+} // namespace testing
+} // namespace bindings
+} // namespace cobalt
diff --git a/src/cobalt/bindings/testing/testing.gyp b/src/cobalt/bindings/testing/testing.gyp
index 49c20e4..b820608 100644
--- a/src/cobalt/bindings/testing/testing.gyp
+++ b/src/cobalt/bindings/testing/testing.gyp
@@ -139,6 +139,7 @@
'operations_bindings_test.cc',
'optional_arguments_bindings_test.cc',
'put_forwards_test.cc',
+ 'stack_trace_test.cc',
'static_properties_bindings_test.cc',
'stringifier_bindings_test.cc',
'union_type_bindings_test.cc',
diff --git a/src/cobalt/bindings/testing/window.h b/src/cobalt/bindings/testing/window.h
index 8c6dded..0bc8115 100644
--- a/src/cobalt/bindings/testing/window.h
+++ b/src/cobalt/bindings/testing/window.h
@@ -17,7 +17,12 @@
#ifndef COBALT_BINDINGS_TESTING_WINDOW_H_
#define COBALT_BINDINGS_TESTING_WINDOW_H_
+#include <string>
+#include <vector>
+
#include "cobalt/bindings/testing/global_interface_parent.h"
+#include "cobalt/script/environment_settings.h"
+#include "cobalt/script/global_object_proxy.h"
namespace cobalt {
namespace bindings {
@@ -29,6 +34,12 @@
virtual std::string window_property() { return ""; }
virtual void set_window_property(const std::string&) {}
+ std::string GetStackTrace(
+ const std::vector<script::StackFrame>& stack_frame) {
+ return StackTraceToString(stack_frame);
+ }
+ scoped_refptr<Window> window() { return this; }
+
DEFINE_WRAPPABLE_TYPE(Window);
};
diff --git a/src/cobalt/browser/application.cc b/src/cobalt/browser/application.cc
index 5ec73ec..4327e96 100644
--- a/src/cobalt/browser/application.cc
+++ b/src/cobalt/browser/application.cc
@@ -36,7 +36,7 @@
#include "cobalt/loader/image/image_decoder.h"
#include "cobalt/math/size.h"
#include "cobalt/network/network_event.h"
-#if defined(ENABLE_COMMAND_LINE_SWITCHES)
+#if defined(ENABLE_DEBUG_COMMAND_LINE_SWITCHES)
#include "cobalt/storage/savegame_fake.h"
#endif
#include "cobalt/system_window/application_event.h"
@@ -45,7 +45,7 @@
#if defined(__LB_SHELL__)
#if !defined(__LB_SHELL__FOR_RELEASE__)
#include "lbshell/src/lb_memory_manager.h"
-#endif // defined(ENABLE_DEBUG_CONSOLE)
+#endif // defined(__LB_SHELL__FOR_RELEASE__)
#include "lbshell/src/lb_memory_pages.h"
#endif // defined(__LB_SHELL__)
@@ -64,7 +64,7 @@
int GetRemoteDebuggingPort() {
const int kDefaultRemoteDebuggingPort = 9222;
int remote_debugging_port = kDefaultRemoteDebuggingPort;
-#if defined(ENABLE_COMMAND_LINE_SWITCHES)
+#if defined(ENABLE_DEBUG_COMMAND_LINE_SWITCHES)
CommandLine* command_line = CommandLine::ForCurrentProcess();
if (command_line->HasSwitch(switches::kRemoteDebuggingPort)) {
const std::string switchValue =
@@ -76,13 +76,13 @@
remote_debugging_port = kDefaultRemoteDebuggingPort;
}
}
-#endif // ENABLE_COMMAND_LINE_SWITCHES
+#endif // ENABLE_DEBUG_COMMAND_LINE_SWITCHES
return remote_debugging_port;
}
#endif // ENABLE_REMOTE_DEBUGGING
#if defined(ENABLE_WEBDRIVER)
-#if defined(ENABLE_COMMAND_LINE_SWITCHES)
+#if defined(ENABLE_DEBUG_COMMAND_LINE_SWITCHES)
int GetWebDriverPort() {
// The default port on which the webdriver server should listen for incoming
// connections.
@@ -101,11 +101,11 @@
}
return webdriver_port;
}
-#endif // ENABLE_COMMAND_LINE_SWITCHES
+#endif // ENABLE_DEBUG_COMMAND_LINE_SWITCHES
#endif // ENABLE_WEBDRIVER
GURL GetInitialURL() {
-#if defined(ENABLE_COMMAND_LINE_SWITCHES)
+#if defined(ENABLE_DEBUG_COMMAND_LINE_SWITCHES)
// Allow the user to override the default URL via a command line parameter.
CommandLine* command_line = CommandLine::ForCurrentProcess();
if (command_line->HasSwitch(switches::kInitialURL)) {
@@ -116,13 +116,13 @@
DLOG(INFO) << "URL from parameter is not valid, using default URL.";
}
}
-#endif // ENABLE_COMMAND_LINE_SWITCHES
+#endif // ENABLE_DEBUG_COMMAND_LINE_SWITCHES
return GURL(kDefaultURL);
}
base::TimeDelta GetTimedTraceDuration() {
-#if defined(ENABLE_COMMAND_LINE_SWITCHES)
+#if defined(ENABLE_DEBUG_COMMAND_LINE_SWITCHES)
CommandLine* command_line = CommandLine::ForCurrentProcess();
int duration_in_seconds = 0;
if (command_line->HasSwitch(switches::kTimedTrace) &&
@@ -131,7 +131,7 @@
&duration_in_seconds)) {
return base::TimeDelta::FromSeconds(duration_in_seconds);
}
-#endif // ENABLE_COMMAND_LINE_SWITCHES
+#endif // ENABLE_DEBUG_COMMAND_LINE_SWITCHES
return base::TimeDelta();
}
@@ -140,7 +140,7 @@
// Default is empty, command line can override.
FilePath result;
-#if defined(ENABLE_COMMAND_LINE_SWITCHES)
+#if defined(ENABLE_DEBUG_COMMAND_LINE_SWITCHES)
CommandLine* command_line = CommandLine::ForCurrentProcess();
if (command_line->HasSwitch(switches::kExtraWebFileDir)) {
result =
@@ -153,18 +153,19 @@
}
DLOG(INFO) << "Extra web file dir: " << result.value();
}
-#endif // ENABLE_COMMAND_LINE_SWITCHES
+#endif // ENABLE_DEBUG_COMMAND_LINE_SWITCHES
return result;
}
-#if defined(ENABLE_COMMAND_LINE_SWITCHES)
+#if defined(ENABLE_DEBUG_COMMAND_LINE_SWITCHES)
void EnableUsingStubImageDecoderIfRequired() {
CommandLine* command_line = CommandLine::ForCurrentProcess();
if (command_line->HasSwitch(switches::kStubImageDecoder)) {
loader::image::ImageDecoder::UseStubImageDecoder();
}
}
+#endif // ENABLE_DEBUG_COMMAND_LINE_SWITCHES
void SetIntegerIfSwitchIsSet(const char* switch_name, int* output) {
if (CommandLine::ForCurrentProcess()->HasSwitch(switch_name)) {
@@ -190,7 +191,13 @@
SetIntegerIfSwitchIsSet(browser::switches::kSkiaCacheSizeInBytes,
&options->skia_cache_size_in_bytes);
}
-#endif // ENABLE_COMMAND_LINE_SWITCHES
+
+void ApplyCommandLineSettingsToWebModuleOptions(WebModule::Options* options) {
+ SetIntegerIfSwitchIsSet(browser::switches::kImageCacheSizeInBytes,
+ &options->image_cache_capacity);
+ SetIntegerIfSwitchIsSet(browser::switches::kRemoteTypefaceCacheSizeInBytes,
+ &options->remote_typeface_cache_capacity);
+}
// Restrict navigation to a couple of whitelisted URLs by default.
const char kYouTubeTvLocationPolicy[] =
@@ -288,11 +295,13 @@
options.language = language;
options.network_module_options.preferred_language = language;
-#if defined(ENABLE_COMMAND_LINE_SWITCHES)
ApplyCommandLineSettingsToRendererOptions(&options.renderer_module_options);
+ ApplyCommandLineSettingsToWebModuleOptions(&options.web_module_options);
- if (CommandLine::ForCurrentProcess()->HasSwitch(
- browser::switches::kNullSavegame)) {
+ CommandLine* command_line = CommandLine::ForCurrentProcess();
+
+#if defined(ENABLE_DEBUG_COMMAND_LINE_SWITCHES)
+ if (command_line->HasSwitch(browser::switches::kNullSavegame)) {
options.storage_manager_options.savegame_options.factory =
&storage::SavegameFake::Create;
}
@@ -311,8 +320,7 @@
math::Size viewport_size(kDefaultViewportWidth, kDefaultViewportHeight);
-#if defined(ENABLE_COMMAND_LINE_SWITCHES)
- CommandLine* command_line = CommandLine::ForCurrentProcess();
+#if defined(ENABLE_DEBUG_COMMAND_LINE_SWITCHES)
if (command_line->HasSwitch(browser::switches::kProxy)) {
options.network_module_options.custom_proxy =
command_line->GetSwitchValueASCII(browser::switches::kProxy);
@@ -344,6 +352,20 @@
EnableUsingStubImageDecoderIfRequired();
+ if (command_line->HasSwitch(switches::kAudioDecoderStub)) {
+ DLOG(INFO) << "Use ShellRawAudioDecoderStub";
+ options.media_module_options.use_audio_decoder_stub = true;
+ }
+ if (command_line->HasSwitch(switches::kNullAudioStreamer)) {
+ DLOG(INFO) << "Use null audio";
+ options.media_module_options.use_null_audio_streamer = true;
+ }
+ if (command_line->HasSwitch(switches::kVideoDecoderStub)) {
+ DLOG(INFO) << "Use ShellRawVideoDecoderStub";
+ options.media_module_options.use_video_decoder_stub = true;
+ }
+#endif // ENABLE_DEBUG_COMMAND_LINE_SWITCHES
+
if (command_line->HasSwitch(browser::switches::kViewport)) {
const std::string switchValue =
command_line->GetSwitchValueASCII(browser::switches::kViewport);
@@ -381,19 +403,6 @@
}
}
}
- if (command_line->HasSwitch(switches::kAudioDecoderStub)) {
- DLOG(INFO) << "Use ShellRawAudioDecoderStub";
- options.media_module_options.use_audio_decoder_stub = true;
- }
- if (command_line->HasSwitch(switches::kNullAudioStreamer)) {
- DLOG(INFO) << "Use null audio";
- options.media_module_options.use_null_audio_streamer = true;
- }
- if (command_line->HasSwitch(switches::kVideoDecoderStub)) {
- DLOG(INFO) << "Use ShellRawVideoDecoderStub";
- options.media_module_options.use_video_decoder_stub = true;
- }
-#endif // ENABLE_COMMAND_LINE_SWITCHES
system_window_ =
system_window::CreateSystemWindow(&event_dispatcher_, viewport_size);
@@ -419,7 +428,7 @@
application_event_callback_);
#if defined(ENABLE_WEBDRIVER)
-#if defined(ENABLE_COMMAND_LINE_SWITCHES)
+#if defined(ENABLE_DEBUG_COMMAND_LINE_SWITCHES)
if (command_line->HasSwitch(switches::kEnableWebDriver)) {
int webdriver_port = GetWebDriverPort();
web_driver_module_.reset(new webdriver::WebDriverModule(
@@ -431,7 +440,7 @@
base::Unretained(browser_module_.get())),
base::Bind(&Application::Quit, base::Unretained(this))));
}
-#endif // ENABLE_COMMAND_LINE_SWITCHES
+#endif // ENABLE_DEBUG_COMMAND_LINE_SWITCHES
#endif // ENABLE_WEBDRIVER
#if defined(ENABLE_REMOTE_DEBUGGING)
@@ -442,7 +451,7 @@
base::Unretained(browser_module_.get()))));
#endif // ENABLE_REMOTE_DEBUGGING
-#if defined(ENABLE_COMMAND_LINE_SWITCHES)
+#if defined(ENABLE_DEBUG_COMMAND_LINE_SWITCHES)
int duration_in_seconds = 0;
if (command_line->HasSwitch(switches::kShutdownAfter) &&
base::StringToInt(
@@ -455,7 +464,7 @@
FROM_HERE, quit_closure_,
base::TimeDelta::FromSeconds(duration_in_seconds));
}
-#endif // ENABLE_COMMAND_LINE_SWITCHES
+#endif // ENABLE_DEBUG_COMMAND_LINE_SWITCHES
}
Application::~Application() {
@@ -526,25 +535,15 @@
if (app_event->type() == system_window::ApplicationEvent::kQuit) {
DLOG(INFO) << "Got quit event.";
app_status_ = kWillQuitAppStatus;
-#if !defined(OS_STARBOARD)
- browser_module_->SetWillQuit();
- browser_module_->SetPaused(false);
-#endif // !defined(OS_STARBOARD)
Quit();
} else if (app_event->type() == system_window::ApplicationEvent::kSuspend) {
DLOG(INFO) << "Got suspend event.";
app_status_ = kPausedAppStatus;
++app_suspend_count_;
-#if !defined(OS_STARBOARD)
- browser_module_->SetPaused(true);
-#endif // !defined(OS_STARBOARD)
} else if (app_event->type() == system_window::ApplicationEvent::kResume) {
DLOG(INFO) << "Got resume event.";
app_status_ = kRunningAppStatus;
++app_resume_count_;
-#if !defined(OS_STARBOARD)
- browser_module_->SetPaused(false);
-#endif // !defined(OS_STARBOARD)
}
}
@@ -629,7 +628,7 @@
static_cast<size_t>(memory_info.application_memory);
c_val_stats_.exe_memory = static_cast<size_t>(memory_info.executable_size);
}
-#endif // defined(ENABLE_DEBUG_CONSOLE)
+#endif // defined(__LB_SHELL__FOR_RELEASE__)
// If the memory stats have not been updated yet, then simply use the
// unallocated memory as the available memory.
if (!memory_stats_updated) {
diff --git a/src/cobalt/browser/browser.gyp b/src/cobalt/browser/browser.gyp
index 58aa11b..36effe7 100644
--- a/src/cobalt/browser/browser.gyp
+++ b/src/cobalt/browser/browser.gyp
@@ -46,6 +46,10 @@
'web_module_stat_tracker.cc',
'web_module_stat_tracker.h',
],
+ 'defines': [
+ 'COBALT_IMAGE_CACHE_SIZE_IN_BYTES=<(image_cache_size_in_bytes)',
+ 'COBALT_REMOTE_TYPEFACE_CACHE_SIZE_IN_BYTES=<(remote_typeface_cache_size_in_bytes)',
+ ],
'dependencies': [
'<(DEPTH)/cobalt/account/account.gyp:account',
'<(DEPTH)/cobalt/audio/audio.gyp:audio',
diff --git a/src/cobalt/browser/browser_bindings.gyp b/src/cobalt/browser/browser_bindings.gyp
index 45d7061..80049c1 100644
--- a/src/cobalt/browser/browser_bindings.gyp
+++ b/src/cobalt/browser/browser_bindings.gyp
@@ -23,6 +23,7 @@
'bindings_dependencies': [
'../h5vcc/h5vcc.gyp:h5vcc',
+ '../webdriver/webdriver.gyp:webdriver',
],
# Bindings for the interfaces in this list will be generated, and there must
@@ -139,6 +140,7 @@
'../dom/Uint32Array.idl',
'../dom/Uint8Array.idl',
'../dom/URL.idl',
+ '../dom/VideoPlaybackQuality.idl',
'../dom/Window.idl',
'../dom/XMLDocument.idl',
'../dom/XMLSerializer.idl',
diff --git a/src/cobalt/browser/browser_module.cc b/src/cobalt/browser/browser_module.cc
index f5abd88..668f3c7 100644
--- a/src/cobalt/browser/browser_module.cc
+++ b/src/cobalt/browser/browser_module.cc
@@ -109,6 +109,9 @@
weak_this_(weak_ptr_factory_.GetWeakPtr())),
self_message_loop_(MessageLoop::current()),
storage_manager_(options.storage_manager_options),
+#if defined(OS_STARBOARD)
+ is_rendered_(false),
+#endif // OS_STARBOARD
renderer_module_(system_window, options.renderer_module_options),
#if defined(ENABLE_GPU_ARRAY_BUFFER_ALLOCATOR)
array_buffer_allocator_(new ResourceProviderArrayBufferAllocator(
@@ -156,12 +159,12 @@
web_module_options_.injected_window_attributes["h5vcc"] =
base::Bind(&CreateH5VCC, h5vcc_settings);
-#if defined(ENABLE_DEBUG_CONSOLE) && defined(ENABLE_COMMAND_LINE_SWITCHES)
+#if defined(ENABLE_DEBUG_CONSOLE) && defined(ENABLE_DEBUG_COMMAND_LINE_SWITCHES)
CommandLine* command_line = CommandLine::ForCurrentProcess();
if (command_line->HasSwitch(switches::kInputFuzzer)) {
OnFuzzerToggle(std::string());
}
-#endif // ENABLE_DEBUG_CONSOLE && ENABLE_COMMAND_LINE_SWITCHES
+#endif // ENABLE_DEBUG_CONSOLE && ENABLE_DEBUG_COMMAND_LINE_SWITCHES
input_device_manager_ = input::InputDeviceManager::CreateFromWindow(
base::Bind(&BrowserModule::OnKeyEventProduced, base::Unretained(this)),
@@ -266,49 +269,6 @@
return web_module_loaded_.TimedWait(timeout);
}
-void BrowserModule::SetPaused(bool paused) {
- // This method should not be called on the browser's own thread, as
- // we will be unable to signal the |has_resumed_| event when the
- // |Pause| method blocks the thread.
- DCHECK_NE(MessageLoop::current(), self_message_loop_);
-
- if (paused) {
- has_resumed_.Reset();
- self_message_loop_->PostTask(
- FROM_HERE, base::Bind(&BrowserModule::Pause, base::Unretained(this)));
- } else {
- has_resumed_.Signal();
- }
-}
-
-void BrowserModule::SetWillQuit() {
- base::AutoLock lock(quit_lock_);
- will_quit_ = true;
-}
-
-bool BrowserModule::WillQuit() {
- base::AutoLock lock(quit_lock_);
- return will_quit_;
-}
-
-void BrowserModule::Pause() {
- // This method must be called on the browser's own thread.
- DCHECK_EQ(MessageLoop::current(), self_message_loop_);
-
- media_module_->PauseAllPlayers();
-
- // Block the thread until the browser has been resumed.
- DLOG(INFO) << "Pausing browser loop with " << self_message_loop_->Size()
- << " items in queue.";
- has_resumed_.Wait();
- DLOG(INFO) << "Resuming browser loop with " << self_message_loop_->Size()
- << " items in queue.";
-
- if (!WillQuit()) {
- media_module_->ResumeAllPlayers();
- }
-}
-
#if defined(ENABLE_SCREENSHOT)
void BrowserModule::RequestScreenshotToFile(const FilePath& path,
const base::Closure& done_cb) {
@@ -325,14 +285,17 @@
void BrowserModule::OnRenderTreeProduced(
const browser::WebModule::LayoutResults& layout_results) {
TRACE_EVENT0("cobalt::browser", "BrowserModule::OnRenderTreeProduced()");
- render_tree_combiner_.UpdateMainRenderTree(renderer::Submission(
- layout_results.render_tree, layout_results.animations,
- layout_results.layout_time));
+ renderer::Submission renderer_submission(layout_results.render_tree,
+ layout_results.layout_time);
+#if defined(OS_STARBOARD)
+ renderer_submission.on_rasterized_callback = base::Bind(
+ &BrowserModule::OnRendererSubmissionRasterized, base::Unretained(this));
+#endif // OS_STARBOARD
+ render_tree_combiner_.UpdateMainRenderTree(renderer_submission);
#if defined(ENABLE_SCREENSHOT)
screen_shot_writer_->SetLastPipelineSubmission(renderer::Submission(
- layout_results.render_tree, layout_results.animations,
- layout_results.layout_time));
+ layout_results.render_tree, layout_results.layout_time));
#endif
}
@@ -361,8 +324,7 @@
TRACE_EVENT0("cobalt::browser",
"BrowserModule::OnDebugConsoleRenderTreeProduced()");
render_tree_combiner_.UpdateDebugConsoleRenderTree(renderer::Submission(
- layout_results.render_tree, layout_results.animations,
- layout_results.layout_time));
+ layout_results.render_tree, layout_results.layout_time));
}
#endif // defined(ENABLE_DEBUG_CONSOLE)
@@ -550,5 +512,15 @@
network_module_.SetProxy(proxy_rules);
}
+#if defined(OS_STARBOARD)
+void BrowserModule::OnRendererSubmissionRasterized() {
+ if (!is_rendered_) {
+ // Hide the system splash screen when the first render has completed.
+ is_rendered_ = true;
+ SbSystemHideSplashScreen();
+ }
+}
+#endif // OS_STARBOARD
+
} // namespace browser
} // namespace cobalt
diff --git a/src/cobalt/browser/browser_module.h b/src/cobalt/browser/browser_module.h
index aadc0af..4ae4fb4 100644
--- a/src/cobalt/browser/browser_module.h
+++ b/src/cobalt/browser/browser_module.h
@@ -86,17 +86,6 @@
void AddURLHandler(const URLHandler::URLHandlerCallback& callback);
void RemoveURLHandler(const URLHandler::URLHandlerCallback& callback);
- // Pauses/resumes all media players and blocks the browser thread. Should
- // be called on a thread other than |self_message_loop_|.
- void SetPaused(bool paused);
-
- // Lets the web browser know that the application is about to quit. We use
- // this not to start the web players when the thread is unpaused.
- void SetWillQuit();
-
- // Whether |SetWillQuit| has been called.
- bool WillQuit();
-
#if defined(ENABLE_SCREENSHOT)
// Request a screenshot to be written to the specified path. Callback will
// be fired after the screenshot has been written to disk.
@@ -172,10 +161,6 @@
// Destroys the splash screen, if currently displayed.
void DestroySplashScreen();
- // Pauses all active web players and blocks the main thread until the
- // |has_resumed_| event is signalled. Must be called on |self_message_loop_|.
- void Pause();
-
#if defined(ENABLE_DEBUG_CONSOLE)
// Toggles the input fuzzer on/off. Ignores the parameter.
void OnFuzzerToggle(const std::string&);
@@ -195,6 +180,12 @@
scoped_ptr<webdriver::WindowDriver>* out_window_driver);
#endif
+#if defined(OS_STARBOARD)
+ // Called when a renderer submission has been rasterized. Used to hide the
+ // system splash screen after the first render has completed.
+ void OnRendererSubmissionRasterized();
+#endif // OS_STARBOARD
+
// 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
@@ -222,6 +213,12 @@
storage::StorageManager storage_manager_;
+#if defined(OS_STARBOARD)
+ // Whether the browser module has yet rendered anything. On the very first
+ // render, we hide the system splash screen.
+ bool is_rendered_;
+#endif // OS_STARBOARD
+
// Sets up everything to do with graphics, from backend objects like the
// display and graphics context to the rasterizer and rendering pipeline.
renderer::RendererModule renderer_module_;
diff --git a/src/cobalt/browser/debug_console.cc b/src/cobalt/browser/debug_console.cc
index 0fce499..a293be3 100644
--- a/src/cobalt/browser/debug_console.cc
+++ b/src/cobalt/browser/debug_console.cc
@@ -77,14 +77,14 @@
// Returns the debug console mode as specified by the command line.
// If unspecified by the command line, base::nullopt is returned.
base::optional<int> GetDebugConsoleModeFromCommandLine() {
-#if defined(ENABLE_COMMAND_LINE_SWITCHES)
+#if defined(ENABLE_DEBUG_COMMAND_LINE_SWITCHES)
CommandLine* command_line = CommandLine::ForCurrentProcess();
if (command_line->HasSwitch(switches::kDebugConsoleMode)) {
const std::string debug_console_mode_string =
command_line->GetSwitchValueASCII(switches::kDebugConsoleMode);
return DebugConsoleModeStringToInt(debug_console_mode_string);
}
-#endif // ENABLE_COMMAND_LINE_SWITCHES
+#endif // ENABLE_DEBUG_COMMAND_LINE_SWITCHES
return base::nullopt;
}
diff --git a/src/cobalt/browser/starboard/event_handler.cc b/src/cobalt/browser/starboard/event_handler.cc
index 4ef7069..00808d7 100644
--- a/src/cobalt/browser/starboard/event_handler.cc
+++ b/src/cobalt/browser/starboard/event_handler.cc
@@ -18,6 +18,7 @@
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
+#include "cobalt/network/network_event.h"
#include "cobalt/system_window/application_event.h"
#include "cobalt/system_window/starboard/system_window.h"
@@ -58,6 +59,12 @@
} else if (starboard_event->type == kSbEventTypeSuspend) {
cobalt_event.reset(new system_window::ApplicationEvent(
system_window::ApplicationEvent::kSuspend));
+ } else if (starboard_event->type == kSbEventTypeNetworkConnect) {
+ cobalt_event.reset(
+ new network::NetworkEvent(network::NetworkEvent::kConnection));
+ } else if (starboard_event->type == kSbEventTypeNetworkDisconnect) {
+ cobalt_event.reset(
+ new network::NetworkEvent(network::NetworkEvent::kDisconnection));
}
// Dispatch the Cobalt event, if created.
diff --git a/src/cobalt/browser/switches.cc b/src/cobalt/browser/switches.cc
index 9258a4f..d9d0abf 100644
--- a/src/cobalt/browser/switches.cc
+++ b/src/cobalt/browser/switches.cc
@@ -20,7 +20,7 @@
namespace browser {
namespace switches {
-#if defined(ENABLE_COMMAND_LINE_SWITCHES)
+#if defined(ENABLE_DEBUG_COMMAND_LINE_SWITCHES)
// Allow insecure HTTP network connections.
const char kAllowHttp[] = "allow_http";
@@ -71,32 +71,13 @@
// Creates a remote debugging server and listens on the specified port.
const char kRemoteDebuggingPort[] = "remote_debugging_port";
-// Determines the capacity of the scratch surface cache. The scratch surface
-// cache facilitates the reuse of temporary offscreen surfaces within a single
-// frame. This setting is only relevant when using the hardware-accelerated
-// Skia rasterizer.
-const char kScratchSurfaceCacheSizeInBytes[] =
- "scratch_surface_cache_size_in_bytes";
-
// If this flag is set, Cobalt will automatically shutdown after the specified
// number of seconds have passed.
const char kShutdownAfter[] = "shutdown_after";
-// Determines the capacity of the skia cache. The Skia cache is maintained
-// within Skia and is used to cache the results of complicated effects such as
-// shadows, so that Skia draw calls that are used repeatedly across frames can
-// be cached into surfaces. This setting is only relevant when using the
-// hardware-accelerated Skia rasterizer.
-const char kSkiaCacheSizeInBytes[] = "skia_cache_size_in_bytes";
-
// Decode all images using StubImageDecoder.
const char kStubImageDecoder[] = "stub_image_decoder";
-// Determines the capacity of the surface cache. The surface cache tracks which
-// render tree nodes are being re-used across frames and stores the nodes that
-// are most CPU-expensive to render into surfaces.
-const char kSurfaceCacheSizeInBytes[] = "surface_cache_size_in_bytes";
-
// If this is set, then a trace (see base/debug/trace_eventh.h) is started on
// Cobalt startup. A value must also be specified for this switch, which is
// the duration in seconds of how long the trace will be done for before ending
@@ -104,16 +85,48 @@
// "timed_trace.json" in the log output directory.
const char kTimedTrace[] = "timed_trace";
-// Specifies the viewport size: width ['x' height]
-const char kViewport[] = "viewport";
-
// Decode video data using ShellRawVideoDecoderStub.
extern const char kVideoDecoderStub[] = "video_decoder_stub";
// Port that the WebDriver server should be listening on.
const char kWebDriverPort[] = "webdriver_port";
-#endif // ENABLE_COMMAND_LINE_SWITCHES
+#endif // ENABLE_DEBUG_COMMAND_LINE_SWITCHES
+
+// Determines the capacity of the image cache which manages image surfaces
+// downloaded from a web page. While it depends on the platform, often (and
+// ideally) these images are cached within GPU memory.
+const char kImageCacheSizeInBytes[] = "image_cache_size_in_bytes";
+
+// Determines the capacity of the remote typefaces cache which manages all
+// typefaces downloaded from a web page.
+const char kRemoteTypefaceCacheSizeInBytes[] =
+ "remote_typeface_cache_size_in_bytes";
+
+// Determines the capacity of the scratch surface cache. The scratch surface
+// cache facilitates the reuse of temporary offscreen surfaces within a single
+// frame. This setting is only relevant when using the hardware-accelerated
+// Skia rasterizer. While it depends on the platform, this setting may affect
+// GPU memory usage.
+const char kScratchSurfaceCacheSizeInBytes[] =
+ "scratch_surface_cache_size_in_bytes";
+
+// Determines the capacity of the skia cache. The Skia cache is maintained
+// within Skia and is used to cache the results of complicated effects such as
+// shadows, so that Skia draw calls that are used repeatedly across frames can
+// be cached into surfaces. This setting is only relevant when using the
+// hardware-accelerated Skia rasterizer. While it depends on the platform, this
+// setting may affect GPU memory usage.
+const char kSkiaCacheSizeInBytes[] = "skia_cache_size_in_bytes";
+
+// Determines the capacity of the surface cache. The surface cache tracks which
+// render tree nodes are being re-used across frames and stores the nodes that
+// are most CPU-expensive to render into surfaces. While it depends on the
+// platform, this setting may affect GPU memory usage.
+const char kSurfaceCacheSizeInBytes[] = "surface_cache_size_in_bytes";
+
+// Specifies the viewport size: width ['x' height]
+const char kViewport[] = "viewport";
} // namespace switches
} // namespace browser
diff --git a/src/cobalt/browser/switches.h b/src/cobalt/browser/switches.h
index 4c66e0c..75dc57d 100644
--- a/src/cobalt/browser/switches.h
+++ b/src/cobalt/browser/switches.h
@@ -21,7 +21,7 @@
namespace browser {
namespace switches {
-#if defined(ENABLE_COMMAND_LINE_SWITCHES)
+#if defined(ENABLE_DEBUG_COMMAND_LINE_SWITCHES)
extern const char kAllowHttp[];
extern const char kAudioDecoderStub[];
extern const char kCspMode[];
@@ -39,13 +39,16 @@
extern const char kShutdownAfter[];
extern const char kStubImageDecoder[];
extern const char kTimedTrace[];
-extern const char kViewport[];
extern const char kVideoDecoderStub[];
extern const char kWebDriverPort[];
-extern const char kSurfaceCacheSizeInBytes[];
+#endif // ENABLE_DEBUG_COMMAND_LINE_SWITCHES
+
+extern const char kImageCacheSizeInBytes[];
+extern const char kRemoteTypefaceCacheSizeInBytes[];
extern const char kScratchSurfaceCacheSizeInBytes[];
extern const char kSkiaCacheSizeInBytes[];
-#endif // ENABLE_COMMAND_LINE_SWITCHES
+extern const char kSurfaceCacheSizeInBytes[];
+extern const char kViewport[];
} // namespace switches
} // namespace browser
diff --git a/src/cobalt/browser/web_module.cc b/src/cobalt/browser/web_module.cc
index 88b5286..828380d 100644
--- a/src/cobalt/browser/web_module.cc
+++ b/src/cobalt/browser/web_module.cc
@@ -246,16 +246,18 @@
data.network_module, data.options.extra_web_file_dir));
DCHECK(fetcher_factory_);
+ DCHECK_LE(0, data.options.image_cache_capacity);
image_cache_ = loader::image::CreateImageCache(
base::StringPrintf("Memory.%s.ImageCache", name_.c_str()),
- data.options.image_cache_capacity, data.resource_provider,
- fetcher_factory_.get());
+ static_cast<uint32>(data.options.image_cache_capacity),
+ data.resource_provider, fetcher_factory_.get());
DCHECK(image_cache_);
+ DCHECK_LE(0, data.options.remote_typeface_cache_capacity);
remote_typeface_cache_ = loader::font::CreateRemoteTypefaceCache(
base::StringPrintf("Memory.%s.RemoteTypefaceCache", name_.c_str()),
- kRemoteTypefaceCacheCapacity, data.resource_provider,
- fetcher_factory_.get());
+ static_cast<uint32>(data.options.remote_typeface_cache_capacity),
+ data.resource_provider, fetcher_factory_.get());
DCHECK(remote_typeface_cache_);
local_storage_database_.reset(
@@ -512,6 +514,16 @@
web_module_->impl_.reset();
}
+WebModule::Options::Options()
+ : name("WebModule"),
+ layout_trigger(layout::LayoutManager::kOnDocumentMutation),
+ image_cache_capacity(COBALT_IMAGE_CACHE_SIZE_IN_BYTES),
+ remote_typeface_cache_capacity(
+ COBALT_REMOTE_TYPEFACE_CACHE_SIZE_IN_BYTES),
+ csp_enforcement_mode(dom::kCspEnforcementEnable),
+ csp_insecure_allowed_token(0),
+ track_event_stats(false) {}
+
WebModule::WebModule(
const GURL& initial_url,
const OnRenderTreeProducedCallback& render_tree_produced_callback,
diff --git a/src/cobalt/browser/web_module.h b/src/cobalt/browser/web_module.h
index 83cfa49..826df99 100644
--- a/src/cobalt/browser/web_module.h
+++ b/src/cobalt/browser/web_module.h
@@ -74,11 +74,6 @@
// accessed from only one thread.
class WebModule {
public:
- // TODO: These numbers should be adjusted according to the size of
- // client memory.
- static const uint32 kImageCacheCapacity = 64U * 1024 * 1024;
- static const uint32 kRemoteTypefaceCacheCapacity = 5U * 1024 * 1024;
-
struct Options {
typedef base::Callback<scoped_refptr<script::Wrappable>()>
CreateObjectFunction;
@@ -86,15 +81,8 @@
InjectedWindowAttributes;
// All optional parameters defined in this structure should have their
- // values
- // initialized in the default constructor to useful defaults.
- Options()
- : name("WebModule"),
- layout_trigger(layout::LayoutManager::kOnDocumentMutation),
- image_cache_capacity(kImageCacheCapacity),
- csp_enforcement_mode(dom::kCspEnforcementEnable),
- csp_insecure_allowed_token(0),
- track_event_stats(false) {}
+ // values initialized in the default constructor to useful defaults.
+ Options();
// The name of the WebModule. This is useful for debugging purposes as in
// the case where multiple WebModule objects exist, it can be used to
@@ -133,7 +121,10 @@
std::string location_policy;
// Image cache capaticy in bytes.
- uint32 image_cache_capacity;
+ int image_cache_capacity;
+
+ // Typeface cache capacity in bytes.
+ int remote_typeface_cache_capacity;
// Content Security Policy enforcement mode for this web module.
dom::CspEnforcementType csp_enforcement_mode;
diff --git a/src/cobalt/build/build.id b/src/cobalt/build/build.id
index 4db8c83..29fb020 100644
--- a/src/cobalt/build/build.id
+++ b/src/cobalt/build/build.id
@@ -1 +1 @@
-9617
\ No newline at end of file
+10060
\ No newline at end of file
diff --git a/src/cobalt/build/config/base.gypi b/src/cobalt/build/config/base.gypi
index ae3ac78..04a0d5e 100644
--- a/src/cobalt/build/config/base.gypi
+++ b/src/cobalt/build/config/base.gypi
@@ -106,11 +106,27 @@
# "cobalt/renderer/egl_and_gles/egl_and_gles_<gl_type>.gyp not found"
'gl_type%': 'system_gles2',
+ # Cache parameters
+
+ # The following set of parameters define how much memory is reserved for
+ # different Cobalt caches. These caches affect CPU *and* GPU memory usage.
+ #
+ # The sum of the following caches effectively describes the maximum GPU
+ # texture memory usage (though it doesn't consider video textures and
+ # display color buffers):
+ # - skia_cache_size_in_bytes (GLES2 rasterizer only)
+ # - scratch_surface_cache_size_in_bytes
+ # - surface_cache_size_in_bytes
+ # - image_cache_size_in_bytes
+ #
+ # The other caches affect CPU memory usage.
+
# Determines the capacity of the skia cache. The Skia cache is maintained
# within Skia and is used to cache the results of complicated effects such
# as shadows, so that Skia draw calls that are used repeatedly across
# frames can be cached into surfaces. This setting is only relevant when
- # using the hardware-accelerated Skia rasterizer.
+ # using the hardware-accelerated Skia rasterizer (e.g. as opposed to the
+ # Blitter API).
'skia_cache_size_in_bytes%': 4 * 1024 * 1024,
# Determines the capacity of the scratch surface cache. The scratch
@@ -124,6 +140,15 @@
# nodes that are most CPU-expensive to render into surfaces.
'surface_cache_size_in_bytes%': 0,
+ # Determines the capacity of the image cache which manages image surfaces
+ # downloaded from a web page. While it depends on the platform, often (and
+ # ideally) these images are cached within GPU memory.
+ 'image_cache_size_in_bytes%': 64 * 1024 * 1024,
+
+ # Determines the capacity of the remote typefaces cache which manages all
+ # typefaces downloaded from a web page.
+ 'remote_typeface_cache_size_in_bytes%': 5 * 1024 * 1024,
+
# Compiler configuration.
# The following variables are used to specify compiler and linker
@@ -166,6 +191,11 @@
# as expected, rather than requiring it to be set for each platform.
#'javascript_engine%': 'javascriptcore',
+ # Enable jit by default. It can be set to 0 to run in interpreter-only mode.
+ # Setting this to 1 on a platform or engine for which there is no JIT
+ # implementation is a no-op.
+ 'cobalt_enable_jit%': 1,
+
# Customize variables used by Chromium's build/common.gypi.
# Disable a check that looks for an official google api key.
@@ -287,7 +317,7 @@
'COBALT_BOX_DUMP_ENABLED',
'COBALT_BUILD_TYPE_DEBUG',
'_DEBUG',
- 'ENABLE_COMMAND_LINE_SWITCHES',
+ 'ENABLE_DEBUG_COMMAND_LINE_SWITCHES',
'ENABLE_DEBUG_C_VAL',
'ENABLE_DEBUG_CONSOLE',
'ENABLE_DIR_SOURCE_ROOT_ACCESS',
@@ -310,7 +340,7 @@
'_DEBUG',
'ALLOCATOR_STATS_TRACKING',
'COBALT_BUILD_TYPE_DEVEL',
- 'ENABLE_COMMAND_LINE_SWITCHES',
+ 'ENABLE_DEBUG_COMMAND_LINE_SWITCHES',
'ENABLE_DEBUG_C_VAL',
'ENABLE_DEBUG_CONSOLE',
'ENABLE_DIR_SOURCE_ROOT_ACCESS',
@@ -332,7 +362,7 @@
'defines': [
'ALLOCATOR_STATS_TRACKING',
'COBALT_BUILD_TYPE_QA',
- 'ENABLE_COMMAND_LINE_SWITCHES',
+ 'ENABLE_DEBUG_COMMAND_LINE_SWITCHES',
'ENABLE_DEBUG_C_VAL',
'ENABLE_DEBUG_CONSOLE',
'ENABLE_DIR_SOURCE_ROOT_ACCESS',
diff --git a/src/cobalt/codereview.settings b/src/cobalt/codereview.settings
deleted file mode 100644
index a4b341a..0000000
--- a/src/cobalt/codereview.settings
+++ /dev/null
@@ -1,4 +0,0 @@
-# This file is used by gcl to get repository specific information.
-GERRIT_HOST: lbshell-internal-review.googlesource.com
-GERRIT_AUTODETECT_BRANCH: true
-CODE_REVIEW_SERVER: lbshell-internal-review.googlesource.com
diff --git a/src/cobalt/cssom/animation_set.cc b/src/cobalt/cssom/animation_set.cc
index 37cea7d..a2459bb 100644
--- a/src/cobalt/cssom/animation_set.cc
+++ b/src/cobalt/cssom/animation_set.cc
@@ -99,7 +99,7 @@
}
} // namespace
-void AnimationSet::Update(const base::TimeDelta& current_time,
+bool AnimationSet::Update(const base::TimeDelta& current_time,
const CSSComputedStyleData& style,
const CSSKeyframesRule::NameMap& keyframes_map) {
const std::vector<scoped_refptr<PropertyValue> >& names =
@@ -115,9 +115,12 @@
names[0] == KeywordValue::GetNone()) {
// If we have no current animations playing and no animations were
// specified, there is nothing to do so we can return immediately.
- return;
+ return false;
}
+ // Whether or not the animations have been modified by this update.
+ bool animations_modified = false;
+
// Build a set of all animations in the new declared animation set, so that
// we can later use this to decide which old animations are no longer active.
std::set<std::string> declared_animation_set;
@@ -172,6 +175,8 @@
if (event_handler_) {
event_handler_->OnAnimationStarted(inserted->second);
}
+
+ animations_modified = true;
}
// Finally check for any animations that are now ended.
@@ -189,10 +194,16 @@
animations_to_end.push_back(iter->first);
}
}
- for (std::vector<std::string>::iterator iter = animations_to_end.begin();
- iter != animations_to_end.end(); ++iter) {
- animations_.erase(*iter);
+ if (!animations_to_end.empty()) {
+ for (std::vector<std::string>::iterator iter = animations_to_end.begin();
+ iter != animations_to_end.end(); ++iter) {
+ animations_.erase(*iter);
+ }
+
+ animations_modified = true;
}
+
+ return animations_modified;
}
} // namespace cssom
diff --git a/src/cobalt/cssom/animation_set.h b/src/cobalt/cssom/animation_set.h
index 5ef8cf1..160377b 100644
--- a/src/cobalt/cssom/animation_set.h
+++ b/src/cobalt/cssom/animation_set.h
@@ -48,7 +48,8 @@
// Update the internal state of animations based on our previous state and the
// passed in computed style. Animations may be started or ended when this
// method is called.
- void Update(const base::TimeDelta& current_time,
+ // Returns whether or not the update modified the animations.
+ bool Update(const base::TimeDelta& current_time,
const CSSComputedStyleData& style,
const CSSKeyframesRule::NameMap& keyframes_map);
diff --git a/src/cobalt/cssom/cascaded_style.cc b/src/cobalt/cssom/cascaded_style.cc
index 99511a2..7776979 100644
--- a/src/cobalt/cssom/cascaded_style.cc
+++ b/src/cobalt/cssom/cascaded_style.cc
@@ -69,7 +69,7 @@
scoped_refptr<CSSComputedStyleData> cascaded_style(
new CSSComputedStyleData());
- // A sparce vector of CascadePrecedence values for all possible property
+ // A sparse vector of CascadePrecedence values for all possible property
// values.
base::optional<CascadePrecedence>
cascade_precedences[static_cast<size_t>(kNumLonghandProperties)];
diff --git a/src/cobalt/cssom/computed_style.cc b/src/cobalt/cssom/computed_style.cc
index 30d4986..48d8223 100644
--- a/src/cobalt/cssom/computed_style.cc
+++ b/src/cobalt/cssom/computed_style.cc
@@ -23,6 +23,7 @@
#include "cobalt/cssom/absolute_url_value.h"
#include "cobalt/cssom/calc_value.h"
#include "cobalt/cssom/css_computed_style_data.h"
+#include "cobalt/cssom/css_computed_style_declaration.h"
#include "cobalt/cssom/font_weight_value.h"
#include "cobalt/cssom/keyword_value.h"
#include "cobalt/cssom/length_value.h"
@@ -2484,16 +2485,18 @@
public:
CalculateComputedStyleContext(
CSSComputedStyleData* cascaded_style,
- const scoped_refptr<const CSSComputedStyleData>& parent_computed_style,
+ const scoped_refptr<CSSComputedStyleDeclaration>&
+ parent_computed_style_declaration,
const scoped_refptr<const CSSComputedStyleData>& root_computed_style,
const math::Size& viewport_size,
GURLMap* const property_key_to_base_url_map)
: cascaded_style_(cascaded_style),
- parent_computed_style_(*parent_computed_style),
+ parent_computed_style_(*parent_computed_style_declaration->data()),
root_computed_style_(*root_computed_style),
viewport_size_(viewport_size),
property_key_to_base_url_map_(property_key_to_base_url_map) {
- cascaded_style_->SetParentComputedStyle(parent_computed_style);
+ cascaded_style_->SetParentComputedStyleDeclaration(
+ parent_computed_style_declaration);
}
// Updates the property specified by the iterator to its computed value.
@@ -2689,6 +2692,11 @@
bool CalculateComputedStyleContext::HandleInheritOrInitial(
PropertyKey key, scoped_refptr<PropertyValue>* value) {
if (*value == KeywordValue::GetInherit()) {
+ // Add this property to the list of those that inherited their declared
+ // value from the parent. This allows the computed style to later determine
+ // if a value that was explicitly inherited from the parent is no longer
+ // valid.
+ cascaded_style_->AddDeclaredPropertyInheritedFromParent(key);
*value = parent_computed_style_.GetPropertyValue(key);
return true;
} else if (*value == KeywordValue::GetInitial()) {
@@ -3067,22 +3075,39 @@
void PromoteToComputedStyle(
const scoped_refptr<CSSComputedStyleData>& cascaded_style,
- const scoped_refptr<const CSSComputedStyleData>& parent_computed_style,
+ const scoped_refptr<CSSComputedStyleDeclaration>&
+ parent_computed_style_declaration,
const scoped_refptr<const CSSComputedStyleData>& root_computed_style,
const math::Size& viewport_size,
GURLMap* const property_key_to_base_url_map) {
DCHECK(cascaded_style);
- DCHECK(parent_computed_style);
+ DCHECK(parent_computed_style_declaration);
DCHECK(root_computed_style);
// Create a context for calculating the computed style. This object is useful
// because it can cache computed style values that are depended upon by other
// properties' computed style calculations.
CalculateComputedStyleContext calculate_computed_style_context(
- cascaded_style.get(), parent_computed_style, root_computed_style,
- viewport_size, property_key_to_base_url_map);
+ cascaded_style.get(), parent_computed_style_declaration,
+ root_computed_style, viewport_size, property_key_to_base_url_map);
- // Go through all values declared values and calculate their computed values.
+ // For each inherited, animatable property, set the property value to
+ // inherited if it is not already declared. This causes the value to be
+ // explicitly set within the CSSComputedStyleData and ensures that the
+ // original value will be available for transitions (which need to know the
+ // before and after state of the property) even when the property is inherited
+ // from a parent that has changed.
+ const PropertyKeyVector& inherited_animatable_properties =
+ GetInheritedAnimatableProperties();
+ for (PropertyKeyVector::const_iterator iter =
+ inherited_animatable_properties.begin();
+ iter != inherited_animatable_properties.end(); ++iter) {
+ if (!cascaded_style->IsDeclared(*iter)) {
+ cascaded_style->SetPropertyValue(*iter, KeywordValue::GetInherit());
+ }
+ }
+
+ // Go through all declared values and calculate their computed values.
CSSComputedStyleData::PropertyValues* declared_property_values =
cascaded_style->declared_property_values();
for (CSSComputedStyleData::PropertyValues::iterator property_value_iterator =
@@ -3095,11 +3120,13 @@
}
scoped_refptr<CSSComputedStyleData> GetComputedStyleOfAnonymousBox(
- const scoped_refptr<const CSSComputedStyleData>& parent_computed_style) {
+ const scoped_refptr<CSSComputedStyleDeclaration>&
+ parent_computed_style_declaration) {
scoped_refptr<CSSComputedStyleData> computed_style =
new CSSComputedStyleData();
- PromoteToComputedStyle(computed_style, parent_computed_style,
- parent_computed_style, math::Size(), NULL);
+ PromoteToComputedStyle(computed_style, parent_computed_style_declaration,
+ parent_computed_style_declaration->data(),
+ math::Size(), NULL);
return computed_style;
}
diff --git a/src/cobalt/cssom/computed_style.h b/src/cobalt/cssom/computed_style.h
index 9d356df..da9c9da 100644
--- a/src/cobalt/cssom/computed_style.h
+++ b/src/cobalt/cssom/computed_style.h
@@ -25,6 +25,7 @@
namespace cssom {
class CSSComputedStyleData;
+class CSSComputedStyleDeclaration;
// The computed value is the result of resolving the specified value,
// generally absolutizing it. The computed value is the value that is
@@ -32,11 +33,12 @@
// https://www.w3.org/TR/css-cascade-3/#computed
// Converts specified values into computed values in place.
-// parent_computed_style and root_computed_style cannot be NULL.
+// parent_computed_style_declaration and root_computed_style cannot be NULL.
// property_key_to_base_url_map can be NULL.
void PromoteToComputedStyle(
const scoped_refptr<CSSComputedStyleData>& specified_style,
- const scoped_refptr<const CSSComputedStyleData>& parent_computed_style,
+ const scoped_refptr<CSSComputedStyleDeclaration>&
+ parent_computed_style_declaration,
const scoped_refptr<const CSSComputedStyleData>& root_computed_style,
const math::Size& viewport_size,
GURLMap* const property_key_to_base_url_map);
@@ -49,7 +51,8 @@
// https://www.w3.org/TR/CSS21/visuren.html#anonymous-block-level
// https://www.w3.org/TR/CSS21/visuren.html#anonymous
scoped_refptr<CSSComputedStyleData> GetComputedStyleOfAnonymousBox(
- const scoped_refptr<const CSSComputedStyleData>& parent_computed_style);
+ const scoped_refptr<CSSComputedStyleDeclaration>&
+ parent_computed_style_declaration);
} // namespace cssom
} // namespace cobalt
diff --git a/src/cobalt/cssom/computed_style_test.cc b/src/cobalt/cssom/computed_style_test.cc
index bd71ff9..d499787 100644
--- a/src/cobalt/cssom/computed_style_test.cc
+++ b/src/cobalt/cssom/computed_style_test.cc
@@ -23,6 +23,7 @@
#include "cobalt/cssom/calc_value.h"
#include "cobalt/cssom/css_computed_style_data.h"
#include "cobalt/cssom/css_computed_style_declaration.h"
+#include "cobalt/cssom/font_style_value.h"
#include "cobalt/cssom/font_weight_value.h"
#include "cobalt/cssom/keyword_value.h"
#include "cobalt/cssom/length_value.h"
@@ -39,15 +40,25 @@
namespace cobalt {
namespace cssom {
+scoped_refptr<CSSComputedStyleDeclaration> CreateComputedStyleDeclaration(
+ scoped_refptr<CSSComputedStyleData> computed_style) {
+ scoped_refptr<CSSComputedStyleDeclaration> computed_style_declaration(
+ new CSSComputedStyleDeclaration());
+ computed_style_declaration->SetData(computed_style);
+ return computed_style_declaration;
+}
+
TEST(PromoteToComputedStyle, FontWeightShouldBeBoldAsSpecified) {
scoped_refptr<CSSComputedStyleData> computed_style(
new CSSComputedStyleData());
computed_style->set_font_weight(FontWeightValue::GetBoldAka700());
- scoped_refptr<const CSSComputedStyleData> parent_computed_style(
+ scoped_refptr<CSSComputedStyleData> parent_computed_style(
new CSSComputedStyleData());
+ scoped_refptr<CSSComputedStyleDeclaration> parent_computed_style_declaration(
+ CreateComputedStyleDeclaration(parent_computed_style));
- PromoteToComputedStyle(computed_style, parent_computed_style,
+ PromoteToComputedStyle(computed_style, parent_computed_style_declaration,
parent_computed_style, math::Size(), NULL);
EXPECT_EQ(FontWeightValue::GetBoldAka700(),
@@ -62,8 +73,10 @@
scoped_refptr<CSSComputedStyleData> parent_computed_style(
new CSSComputedStyleData());
parent_computed_style->set_font_size(new LengthValue(100, kPixelsUnit));
+ scoped_refptr<CSSComputedStyleDeclaration> parent_computed_style_declaration(
+ CreateComputedStyleDeclaration(parent_computed_style));
- PromoteToComputedStyle(computed_style, parent_computed_style,
+ PromoteToComputedStyle(computed_style, parent_computed_style_declaration,
parent_computed_style, math::Size(), NULL);
LengthValue* computed_font_size = base::polymorphic_downcast<LengthValue*>(
@@ -81,12 +94,14 @@
scoped_refptr<CSSComputedStyleData> parent_computed_style(
new CSSComputedStyleData());
parent_computed_style->set_font_size(new LengthValue(100, kPixelsUnit));
+ scoped_refptr<CSSComputedStyleDeclaration> parent_computed_style_declaration(
+ CreateComputedStyleDeclaration(parent_computed_style));
scoped_refptr<CSSComputedStyleData> root_computed_style(
new CSSComputedStyleData());
root_computed_style->set_font_size(new LengthValue(200, kPixelsUnit));
- PromoteToComputedStyle(computed_style, parent_computed_style,
+ PromoteToComputedStyle(computed_style, parent_computed_style_declaration,
root_computed_style, math::Size(), NULL);
LengthValue* computed_font_size = base::polymorphic_downcast<LengthValue*>(
@@ -105,8 +120,10 @@
scoped_refptr<CSSComputedStyleData> parent_computed_style(
new CSSComputedStyleData());
+ scoped_refptr<CSSComputedStyleDeclaration> parent_computed_style_declaration(
+ CreateComputedStyleDeclaration(parent_computed_style));
- PromoteToComputedStyle(computed_style, parent_computed_style,
+ PromoteToComputedStyle(computed_style, parent_computed_style_declaration,
parent_computed_style, math::Size(360, 240), NULL);
LengthValue* computed_font_size = base::polymorphic_downcast<LengthValue*>(
@@ -125,10 +142,12 @@
new CSSComputedStyleData());
computed_style->set_font_size(new LengthValue(50, kPixelsUnit));
- scoped_refptr<const CSSComputedStyleData> parent_computed_style(
+ scoped_refptr<CSSComputedStyleData> parent_computed_style(
new CSSComputedStyleData());
+ scoped_refptr<CSSComputedStyleDeclaration> parent_computed_style_declaration(
+ CreateComputedStyleDeclaration(parent_computed_style));
- PromoteToComputedStyle(computed_style, parent_computed_style,
+ PromoteToComputedStyle(computed_style, parent_computed_style_declaration,
parent_computed_style, math::Size(), NULL);
LengthValue* computed_font_size = base::polymorphic_downcast<LengthValue*>(
@@ -142,10 +161,12 @@
new CSSComputedStyleData());
computed_style->set_line_height(KeywordValue::GetNormal());
- scoped_refptr<const CSSComputedStyleData> parent_computed_style(
+ scoped_refptr<CSSComputedStyleData> parent_computed_style(
new CSSComputedStyleData());
+ scoped_refptr<CSSComputedStyleDeclaration> parent_computed_style_declaration(
+ CreateComputedStyleDeclaration(parent_computed_style));
- PromoteToComputedStyle(computed_style, parent_computed_style,
+ PromoteToComputedStyle(computed_style, parent_computed_style_declaration,
parent_computed_style, math::Size(), NULL);
EXPECT_EQ(KeywordValue::GetNormal(), computed_style->line_height());
@@ -160,8 +181,10 @@
scoped_refptr<CSSComputedStyleData> parent_computed_style(
new CSSComputedStyleData());
parent_computed_style->set_font_size(new LengthValue(100, kPixelsUnit));
+ scoped_refptr<CSSComputedStyleDeclaration> parent_computed_style_declaration(
+ CreateComputedStyleDeclaration(parent_computed_style));
- PromoteToComputedStyle(computed_style, parent_computed_style,
+ PromoteToComputedStyle(computed_style, parent_computed_style_declaration,
parent_computed_style, math::Size(), NULL);
LengthValue* computed_line_height = base::polymorphic_downcast<LengthValue*>(
@@ -179,8 +202,10 @@
scoped_refptr<CSSComputedStyleData> parent_computed_style(
new CSSComputedStyleData());
parent_computed_style->set_font_size(new LengthValue(100, kPixelsUnit));
+ scoped_refptr<CSSComputedStyleDeclaration> parent_computed_style_declaration(
+ CreateComputedStyleDeclaration(parent_computed_style));
- PromoteToComputedStyle(computed_style, parent_computed_style,
+ PromoteToComputedStyle(computed_style, parent_computed_style_declaration,
parent_computed_style, math::Size(), NULL);
LengthValue* computed_text_indent = base::polymorphic_downcast<LengthValue*>(
@@ -202,12 +227,14 @@
scoped_refptr<CSSComputedStyleData> parent_computed_style(
new CSSComputedStyleData());
+ scoped_refptr<CSSComputedStyleDeclaration> parent_computed_style_declaration(
+ CreateComputedStyleDeclaration(parent_computed_style));
GURLMap property_key_to_base_url_map;
property_key_to_base_url_map[kBackgroundImageProperty] =
GURL("file:///computed_style_test/style_sheet.css");
- PromoteToComputedStyle(computed_style, parent_computed_style,
+ PromoteToComputedStyle(computed_style, parent_computed_style_declaration,
parent_computed_style, math::Size(),
&property_key_to_base_url_map);
@@ -237,12 +264,14 @@
scoped_refptr<CSSComputedStyleData> parent_computed_style(
new CSSComputedStyleData());
+ scoped_refptr<CSSComputedStyleDeclaration> parent_computed_style_declaration(
+ CreateComputedStyleDeclaration(parent_computed_style));
GURLMap property_key_to_base_url_map;
property_key_to_base_url_map[kBackgroundImageProperty] =
GURL("file:///computed_style_test/document.html");
- PromoteToComputedStyle(computed_style, parent_computed_style,
+ PromoteToComputedStyle(computed_style, parent_computed_style_declaration,
parent_computed_style, math::Size(),
&property_key_to_base_url_map);
@@ -263,9 +292,12 @@
GetPropertyInitialValue(kBackgroundPositionProperty));
computed_style->set_background_position(background_position);
- scoped_refptr<const CSSComputedStyleData> parent_computed_style(
+ scoped_refptr<CSSComputedStyleData> parent_computed_style(
new CSSComputedStyleData());
- PromoteToComputedStyle(computed_style, parent_computed_style,
+ scoped_refptr<CSSComputedStyleDeclaration> parent_computed_style_declaration(
+ CreateComputedStyleDeclaration(parent_computed_style));
+
+ PromoteToComputedStyle(computed_style, parent_computed_style_declaration,
parent_computed_style, math::Size(), NULL);
scoped_refptr<PropertyListValue> background_position_list =
@@ -302,9 +334,12 @@
new PropertyListValue(background_position_builder.Pass()));
computed_style->set_background_position(background_position);
- scoped_refptr<const CSSComputedStyleData> parent_computed_style(
+ scoped_refptr<CSSComputedStyleData> parent_computed_style(
new CSSComputedStyleData());
- PromoteToComputedStyle(computed_style, parent_computed_style,
+ scoped_refptr<CSSComputedStyleDeclaration> parent_computed_style_declaration(
+ CreateComputedStyleDeclaration(parent_computed_style));
+
+ PromoteToComputedStyle(computed_style, parent_computed_style_declaration,
parent_computed_style, math::Size(), NULL);
scoped_refptr<PropertyListValue> background_position_list =
@@ -340,9 +375,12 @@
new PropertyListValue(background_position_builder.Pass()));
computed_style->set_background_position(background_position);
- scoped_refptr<const CSSComputedStyleData> parent_computed_style(
+ scoped_refptr<CSSComputedStyleData> parent_computed_style(
new CSSComputedStyleData());
- PromoteToComputedStyle(computed_style, parent_computed_style,
+ scoped_refptr<CSSComputedStyleDeclaration> parent_computed_style_declaration(
+ CreateComputedStyleDeclaration(parent_computed_style));
+
+ PromoteToComputedStyle(computed_style, parent_computed_style_declaration,
parent_computed_style, math::Size(), NULL);
scoped_refptr<PropertyListValue> background_position_list =
@@ -380,9 +418,12 @@
new PropertyListValue(background_position_builder.Pass()));
computed_style->set_background_position(background_position);
- scoped_refptr<const CSSComputedStyleData> parent_computed_style(
+ scoped_refptr<CSSComputedStyleData> parent_computed_style(
new CSSComputedStyleData());
- PromoteToComputedStyle(computed_style, parent_computed_style,
+ scoped_refptr<CSSComputedStyleDeclaration> parent_computed_style_declaration(
+ CreateComputedStyleDeclaration(parent_computed_style));
+
+ PromoteToComputedStyle(computed_style, parent_computed_style_declaration,
parent_computed_style, math::Size(), NULL);
scoped_refptr<PropertyListValue> background_position_list =
@@ -419,9 +460,12 @@
new PropertyListValue(background_position_builder.Pass()));
computed_style->set_background_position(background_position);
- scoped_refptr<const CSSComputedStyleData> parent_computed_style(
+ scoped_refptr<CSSComputedStyleData> parent_computed_style(
new CSSComputedStyleData());
- PromoteToComputedStyle(computed_style, parent_computed_style,
+ scoped_refptr<CSSComputedStyleDeclaration> parent_computed_style_declaration(
+ CreateComputedStyleDeclaration(parent_computed_style));
+
+ PromoteToComputedStyle(computed_style, parent_computed_style_declaration,
parent_computed_style, math::Size(), NULL);
scoped_refptr<PropertyListValue> background_position_list =
@@ -458,9 +502,12 @@
new PropertyListValue(background_position_builder.Pass()));
computed_style->set_background_position(background_position);
- scoped_refptr<const CSSComputedStyleData> parent_computed_style(
+ scoped_refptr<CSSComputedStyleData> parent_computed_style(
new CSSComputedStyleData());
- PromoteToComputedStyle(computed_style, parent_computed_style,
+ scoped_refptr<CSSComputedStyleDeclaration> parent_computed_style_declaration(
+ CreateComputedStyleDeclaration(parent_computed_style));
+
+ PromoteToComputedStyle(computed_style, parent_computed_style_declaration,
parent_computed_style, math::Size(), NULL);
scoped_refptr<PropertyListValue> background_position_list =
@@ -497,9 +544,12 @@
new PropertyListValue(background_position_builder.Pass()));
computed_style->set_background_position(background_position);
- scoped_refptr<const CSSComputedStyleData> parent_computed_style(
+ scoped_refptr<CSSComputedStyleData> parent_computed_style(
new CSSComputedStyleData());
- PromoteToComputedStyle(computed_style, parent_computed_style,
+ scoped_refptr<CSSComputedStyleDeclaration> parent_computed_style_declaration(
+ CreateComputedStyleDeclaration(parent_computed_style));
+
+ PromoteToComputedStyle(computed_style, parent_computed_style_declaration,
parent_computed_style, math::Size(), NULL);
scoped_refptr<PropertyListValue> background_position_list =
@@ -537,9 +587,12 @@
new PropertyListValue(background_position_builder.Pass()));
computed_style->set_background_position(background_position);
- scoped_refptr<const CSSComputedStyleData> parent_computed_style(
+ scoped_refptr<CSSComputedStyleData> parent_computed_style(
new CSSComputedStyleData());
- PromoteToComputedStyle(computed_style, parent_computed_style,
+ scoped_refptr<CSSComputedStyleDeclaration> parent_computed_style_declaration(
+ CreateComputedStyleDeclaration(parent_computed_style));
+
+ PromoteToComputedStyle(computed_style, parent_computed_style_declaration,
parent_computed_style, math::Size(), NULL);
scoped_refptr<PropertyListValue> background_position_list =
@@ -577,9 +630,12 @@
new PropertyListValue(background_position_builder.Pass()));
computed_style->set_background_position(background_position);
- scoped_refptr<const CSSComputedStyleData> parent_computed_style(
+ scoped_refptr<CSSComputedStyleData> parent_computed_style(
new CSSComputedStyleData());
- PromoteToComputedStyle(computed_style, parent_computed_style,
+ scoped_refptr<CSSComputedStyleDeclaration> parent_computed_style_declaration(
+ CreateComputedStyleDeclaration(parent_computed_style));
+
+ PromoteToComputedStyle(computed_style, parent_computed_style_declaration,
parent_computed_style, math::Size(), NULL);
scoped_refptr<PropertyListValue> background_position_list =
@@ -618,9 +674,12 @@
new PropertyListValue(background_position_builder.Pass()));
computed_style->set_background_position(background_position);
- scoped_refptr<const CSSComputedStyleData> parent_computed_style(
+ scoped_refptr<CSSComputedStyleData> parent_computed_style(
new CSSComputedStyleData());
- PromoteToComputedStyle(computed_style, parent_computed_style,
+ scoped_refptr<CSSComputedStyleDeclaration> parent_computed_style_declaration(
+ CreateComputedStyleDeclaration(parent_computed_style));
+
+ PromoteToComputedStyle(computed_style, parent_computed_style_declaration,
parent_computed_style, math::Size(), NULL);
scoped_refptr<PropertyListValue> background_position_list =
@@ -656,9 +715,12 @@
new PropertyListValue(background_size_builder.Pass()));
computed_style->set_background_size(background_size);
- scoped_refptr<const CSSComputedStyleData> parent_computed_style(
+ scoped_refptr<CSSComputedStyleData> parent_computed_style(
new CSSComputedStyleData());
- PromoteToComputedStyle(computed_style, parent_computed_style,
+ scoped_refptr<CSSComputedStyleDeclaration> parent_computed_style_declaration(
+ CreateComputedStyleDeclaration(parent_computed_style));
+
+ PromoteToComputedStyle(computed_style, parent_computed_style_declaration,
parent_computed_style, math::Size(), NULL);
scoped_refptr<PropertyListValue> background_size_list =
@@ -682,9 +744,12 @@
new CSSComputedStyleData());
computed_style->set_background_size(KeywordValue::GetContain());
- scoped_refptr<const CSSComputedStyleData> parent_computed_style(
+ scoped_refptr<CSSComputedStyleData> parent_computed_style(
new CSSComputedStyleData());
- PromoteToComputedStyle(computed_style, parent_computed_style,
+ scoped_refptr<CSSComputedStyleDeclaration> parent_computed_style_declaration(
+ CreateComputedStyleDeclaration(parent_computed_style));
+
+ PromoteToComputedStyle(computed_style, parent_computed_style_declaration,
parent_computed_style, math::Size(), NULL);
EXPECT_EQ(KeywordValue::GetContain(), computed_style->background_size());
@@ -695,9 +760,12 @@
new CSSComputedStyleData());
computed_style->set_border_radius(new LengthValue(3, kFontSizesAkaEmUnit));
- scoped_refptr<const CSSComputedStyleData> parent_computed_style(
+ scoped_refptr<CSSComputedStyleData> parent_computed_style(
new CSSComputedStyleData());
- PromoteToComputedStyle(computed_style, parent_computed_style,
+ scoped_refptr<CSSComputedStyleDeclaration> parent_computed_style_declaration(
+ CreateComputedStyleDeclaration(parent_computed_style));
+
+ PromoteToComputedStyle(computed_style, parent_computed_style_declaration,
parent_computed_style, math::Size(), NULL);
LengthValue* border_radius = base::polymorphic_downcast<LengthValue*>(
@@ -712,9 +780,12 @@
computed_style->set_border_left_color(KeywordValue::GetCurrentColor());
computed_style->set_color(RGBAColorValue::GetAqua());
- scoped_refptr<const CSSComputedStyleData> parent_computed_style(
+ scoped_refptr<CSSComputedStyleData> parent_computed_style(
new CSSComputedStyleData());
- PromoteToComputedStyle(computed_style, parent_computed_style,
+ scoped_refptr<CSSComputedStyleDeclaration> parent_computed_style_declaration(
+ CreateComputedStyleDeclaration(parent_computed_style));
+
+ PromoteToComputedStyle(computed_style, parent_computed_style_declaration,
parent_computed_style, math::Size(), NULL);
scoped_refptr<RGBAColorValue> border_color =
@@ -729,9 +800,12 @@
computed_style->set_border_top_style(KeywordValue::GetNone());
computed_style->set_border_top_width(new LengthValue(2, kFontSizesAkaEmUnit));
- scoped_refptr<const CSSComputedStyleData> parent_computed_style(
+ scoped_refptr<CSSComputedStyleData> parent_computed_style(
new CSSComputedStyleData());
- PromoteToComputedStyle(computed_style, parent_computed_style,
+ scoped_refptr<CSSComputedStyleDeclaration> parent_computed_style_declaration(
+ CreateComputedStyleDeclaration(parent_computed_style));
+
+ PromoteToComputedStyle(computed_style, parent_computed_style_declaration,
parent_computed_style, math::Size(), NULL);
scoped_refptr<LengthValue> border_top_width =
@@ -752,7 +826,10 @@
scoped_refptr<CSSComputedStyleData> parent_computed_style(
new CSSComputedStyleData());
parent_computed_style->set_font_size(new LengthValue(100, kPixelsUnit));
- PromoteToComputedStyle(computed_style, parent_computed_style,
+ scoped_refptr<CSSComputedStyleDeclaration> parent_computed_style_declaration(
+ CreateComputedStyleDeclaration(parent_computed_style));
+
+ PromoteToComputedStyle(computed_style, parent_computed_style_declaration,
parent_computed_style, math::Size(), NULL);
scoped_refptr<LengthValue> border_left_width =
@@ -781,7 +858,10 @@
scoped_refptr<CSSComputedStyleData> parent_computed_style(
new CSSComputedStyleData());
parent_computed_style->set_font_size(new LengthValue(50, kPixelsUnit));
- PromoteToComputedStyle(computed_style, parent_computed_style,
+ scoped_refptr<CSSComputedStyleDeclaration> parent_computed_style_declaration(
+ CreateComputedStyleDeclaration(parent_computed_style));
+
+ PromoteToComputedStyle(computed_style, parent_computed_style_declaration,
parent_computed_style, math::Size(), NULL);
scoped_refptr<PropertyListValue> box_shadow_list =
@@ -824,7 +904,10 @@
scoped_refptr<CSSComputedStyleData> parent_computed_style(
new CSSComputedStyleData());
- PromoteToComputedStyle(computed_style, parent_computed_style,
+ scoped_refptr<CSSComputedStyleDeclaration> parent_computed_style_declaration(
+ CreateComputedStyleDeclaration(parent_computed_style));
+
+ PromoteToComputedStyle(computed_style, parent_computed_style_declaration,
parent_computed_style, math::Size(), NULL);
scoped_refptr<PropertyListValue> box_shadow_list =
@@ -867,7 +950,10 @@
scoped_refptr<CSSComputedStyleData> parent_computed_style(
new CSSComputedStyleData());
parent_computed_style->set_color(new RGBAColorValue(0x0047abff));
- PromoteToComputedStyle(computed_style, parent_computed_style,
+ scoped_refptr<CSSComputedStyleDeclaration> parent_computed_style_declaration(
+ CreateComputedStyleDeclaration(parent_computed_style));
+
+ PromoteToComputedStyle(computed_style, parent_computed_style_declaration,
parent_computed_style, math::Size(), NULL);
scoped_refptr<PropertyListValue> box_shadow_list =
@@ -918,7 +1004,10 @@
new CSSComputedStyleData());
parent_computed_style->set_font_size(new LengthValue(50, kPixelsUnit));
parent_computed_style->set_color(new RGBAColorValue(0x0047ABFF));
- PromoteToComputedStyle(computed_style, parent_computed_style,
+ scoped_refptr<CSSComputedStyleDeclaration> parent_computed_style_declaration(
+ CreateComputedStyleDeclaration(parent_computed_style));
+
+ PromoteToComputedStyle(computed_style, parent_computed_style_declaration,
parent_computed_style, math::Size(), NULL);
scoped_refptr<PropertyListValue> box_shadow_list =
@@ -970,7 +1059,10 @@
scoped_refptr<CSSComputedStyleData> parent_computed_style(
new CSSComputedStyleData());
- PromoteToComputedStyle(computed_style, parent_computed_style,
+ scoped_refptr<CSSComputedStyleDeclaration> parent_computed_style_declaration(
+ CreateComputedStyleDeclaration(parent_computed_style));
+
+ PromoteToComputedStyle(computed_style, parent_computed_style_declaration,
parent_computed_style, math::Size(), NULL);
EXPECT_EQ(KeywordValue::GetNone(), computed_style->box_shadow());
@@ -982,9 +1074,12 @@
computed_style->set_text_decoration_color(KeywordValue::GetCurrentColor());
computed_style->set_color(RGBAColorValue::GetAqua());
- scoped_refptr<const CSSComputedStyleData> parent_computed_style(
+ scoped_refptr<CSSComputedStyleData> parent_computed_style(
new CSSComputedStyleData());
- PromoteToComputedStyle(computed_style, parent_computed_style,
+ scoped_refptr<CSSComputedStyleDeclaration> parent_computed_style_declaration(
+ CreateComputedStyleDeclaration(parent_computed_style));
+
+ PromoteToComputedStyle(computed_style, parent_computed_style_declaration,
parent_computed_style, math::Size(), NULL);
scoped_refptr<RGBAColorValue> text_decoration_color =
@@ -1014,7 +1109,10 @@
scoped_refptr<CSSComputedStyleData> parent_computed_style(
new CSSComputedStyleData());
parent_computed_style->set_font_size(new LengthValue(50, kPixelsUnit));
- PromoteToComputedStyle(computed_style, parent_computed_style,
+ scoped_refptr<CSSComputedStyleDeclaration> parent_computed_style_declaration(
+ CreateComputedStyleDeclaration(parent_computed_style));
+
+ PromoteToComputedStyle(computed_style, parent_computed_style_declaration,
parent_computed_style, math::Size(), NULL);
scoped_refptr<PropertyListValue> text_shadow_list =
@@ -1055,7 +1153,10 @@
scoped_refptr<CSSComputedStyleData> parent_computed_style(
new CSSComputedStyleData());
parent_computed_style->set_color(new RGBAColorValue(0x0047abff));
- PromoteToComputedStyle(computed_style, parent_computed_style,
+ scoped_refptr<CSSComputedStyleDeclaration> parent_computed_style_declaration(
+ CreateComputedStyleDeclaration(parent_computed_style));
+
+ PromoteToComputedStyle(computed_style, parent_computed_style_declaration,
parent_computed_style, math::Size(), NULL);
scoped_refptr<PropertyListValue> text_shadow_list =
@@ -1105,7 +1206,10 @@
new CSSComputedStyleData());
parent_computed_style->set_font_size(new LengthValue(50, kPixelsUnit));
parent_computed_style->set_color(new RGBAColorValue(0x0047ABFF));
- PromoteToComputedStyle(computed_style, parent_computed_style,
+ scoped_refptr<CSSComputedStyleDeclaration> parent_computed_style_declaration(
+ CreateComputedStyleDeclaration(parent_computed_style));
+
+ PromoteToComputedStyle(computed_style, parent_computed_style_declaration,
parent_computed_style, math::Size(), NULL);
scoped_refptr<PropertyListValue> text_shadow_list =
@@ -1156,7 +1260,10 @@
scoped_refptr<CSSComputedStyleData> parent_computed_style(
new CSSComputedStyleData());
- PromoteToComputedStyle(computed_style, parent_computed_style,
+ scoped_refptr<CSSComputedStyleDeclaration> parent_computed_style_declaration(
+ CreateComputedStyleDeclaration(parent_computed_style));
+
+ PromoteToComputedStyle(computed_style, parent_computed_style_declaration,
parent_computed_style, math::Size(), NULL);
EXPECT_EQ(KeywordValue::GetNone(), computed_style->text_shadow());
@@ -1171,10 +1278,13 @@
new CSSComputedStyleData());
computed_style->set_height(new PercentageValue(0.50f));
- scoped_refptr<const CSSComputedStyleData> parent_computed_style(
+ scoped_refptr<CSSComputedStyleData> parent_computed_style(
new CSSComputedStyleData());
EXPECT_EQ(KeywordValue::GetAuto(), parent_computed_style->height());
- PromoteToComputedStyle(computed_style, parent_computed_style,
+ scoped_refptr<CSSComputedStyleDeclaration> parent_computed_style_declaration(
+ CreateComputedStyleDeclaration(parent_computed_style));
+
+ PromoteToComputedStyle(computed_style, parent_computed_style_declaration,
parent_computed_style, math::Size(), NULL);
EXPECT_EQ(KeywordValue::GetAuto(), computed_style->height());
@@ -1190,10 +1300,13 @@
new CSSComputedStyleData());
computed_style->set_max_height(new PercentageValue(0.50f));
- scoped_refptr<const CSSComputedStyleData> parent_computed_style(
+ scoped_refptr<CSSComputedStyleData> parent_computed_style(
new CSSComputedStyleData());
EXPECT_EQ(KeywordValue::GetAuto(), parent_computed_style->height());
- PromoteToComputedStyle(computed_style, parent_computed_style,
+ scoped_refptr<CSSComputedStyleDeclaration> parent_computed_style_declaration(
+ CreateComputedStyleDeclaration(parent_computed_style));
+
+ PromoteToComputedStyle(computed_style, parent_computed_style_declaration,
parent_computed_style, math::Size(), NULL);
EXPECT_EQ(KeywordValue::GetNone(), computed_style->max_height());
@@ -1209,10 +1322,13 @@
new CSSComputedStyleData());
computed_style->set_min_height(new PercentageValue(0.50f));
- scoped_refptr<const CSSComputedStyleData> parent_computed_style(
+ scoped_refptr<CSSComputedStyleData> parent_computed_style(
new CSSComputedStyleData());
EXPECT_EQ(KeywordValue::GetAuto(), parent_computed_style->height());
- PromoteToComputedStyle(computed_style, parent_computed_style,
+ scoped_refptr<CSSComputedStyleDeclaration> parent_computed_style_declaration(
+ CreateComputedStyleDeclaration(parent_computed_style));
+
+ PromoteToComputedStyle(computed_style, parent_computed_style_declaration,
parent_computed_style, math::Size(), NULL);
LengthValue* computed_min_height = base::polymorphic_downcast<LengthValue*>(
@@ -1229,15 +1345,22 @@
new CSSComputedStyleData());
computed_style->set_max_width(new PercentageValue(0.50f));
- scoped_refptr<const CSSComputedStyleData> grandparent_computed_style(
+ scoped_refptr<CSSComputedStyleData> grandparent_computed_style(
new CSSComputedStyleData());
+ scoped_refptr<CSSComputedStyleDeclaration>
+ grandparent_computed_style_declaration(
+ CreateComputedStyleDeclaration(grandparent_computed_style));
scoped_refptr<CSSComputedStyleData> parent_computed_style(
new CSSComputedStyleData());
parent_computed_style->set_width(new LengthValue(-16, kPixelsUnit));
- PromoteToComputedStyle(parent_computed_style, grandparent_computed_style,
+ scoped_refptr<CSSComputedStyleDeclaration> parent_computed_style_declaration(
+ CreateComputedStyleDeclaration(parent_computed_style));
+
+ PromoteToComputedStyle(parent_computed_style,
+ grandparent_computed_style_declaration,
grandparent_computed_style, math::Size(), NULL);
- PromoteToComputedStyle(computed_style, parent_computed_style,
+ PromoteToComputedStyle(computed_style, parent_computed_style_declaration,
grandparent_computed_style, math::Size(), NULL);
LengthValue* computed_max_width = base::polymorphic_downcast<LengthValue*>(
@@ -1254,15 +1377,22 @@
new CSSComputedStyleData());
computed_style->set_min_width(new PercentageValue(0.50f));
- scoped_refptr<const CSSComputedStyleData> grandparent_computed_style(
+ scoped_refptr<CSSComputedStyleData> grandparent_computed_style(
new CSSComputedStyleData());
+ scoped_refptr<CSSComputedStyleDeclaration>
+ grandparent_computed_style_declaration(
+ CreateComputedStyleDeclaration(grandparent_computed_style));
scoped_refptr<CSSComputedStyleData> parent_computed_style(
new CSSComputedStyleData());
parent_computed_style->set_width(new LengthValue(-16, kPixelsUnit));
- PromoteToComputedStyle(parent_computed_style, grandparent_computed_style,
+ scoped_refptr<CSSComputedStyleDeclaration> parent_computed_style_declaration(
+ CreateComputedStyleDeclaration(parent_computed_style));
+
+ PromoteToComputedStyle(parent_computed_style,
+ grandparent_computed_style_declaration,
grandparent_computed_style, math::Size(), NULL);
- PromoteToComputedStyle(computed_style, parent_computed_style,
+ PromoteToComputedStyle(computed_style, parent_computed_style_declaration,
grandparent_computed_style, math::Size(), NULL);
LengthValue* computed_min_width = base::polymorphic_downcast<LengthValue*>(
@@ -1280,10 +1410,12 @@
computed_style->set_font_size(new LengthValue(100, kPixelsUnit));
computed_style->set_line_height(new PercentageValue(0.75f));
- scoped_refptr<const CSSComputedStyleData> parent_computed_style(
+ scoped_refptr<CSSComputedStyleData> parent_computed_style(
new CSSComputedStyleData());
+ scoped_refptr<CSSComputedStyleDeclaration> parent_computed_style_declaration(
+ CreateComputedStyleDeclaration(parent_computed_style));
- PromoteToComputedStyle(computed_style, parent_computed_style,
+ PromoteToComputedStyle(computed_style, parent_computed_style_declaration,
parent_computed_style, math::Size(), NULL);
LengthValue* computed_line_height = base::polymorphic_downcast<LengthValue*>(
@@ -1304,9 +1436,12 @@
new PropertyListValue(transform_origin_builder.Pass()));
computed_style->set_transform_origin(transform_origin);
- scoped_refptr<const CSSComputedStyleData> parent_computed_style(
+ scoped_refptr<CSSComputedStyleData> parent_computed_style(
new CSSComputedStyleData());
- PromoteToComputedStyle(computed_style, parent_computed_style,
+ scoped_refptr<CSSComputedStyleDeclaration> parent_computed_style_declaration(
+ CreateComputedStyleDeclaration(parent_computed_style));
+
+ PromoteToComputedStyle(computed_style, parent_computed_style_declaration,
parent_computed_style, math::Size(), NULL);
scoped_refptr<PropertyListValue> transform_origin_list =
@@ -1347,9 +1482,12 @@
new PropertyListValue(transform_origin_builder.Pass()));
computed_style->set_transform_origin(transform_origin);
- scoped_refptr<const CSSComputedStyleData> parent_computed_style(
+ scoped_refptr<CSSComputedStyleData> parent_computed_style(
new CSSComputedStyleData());
- PromoteToComputedStyle(computed_style, parent_computed_style,
+ scoped_refptr<CSSComputedStyleDeclaration> parent_computed_style_declaration(
+ CreateComputedStyleDeclaration(parent_computed_style));
+
+ PromoteToComputedStyle(computed_style, parent_computed_style_declaration,
parent_computed_style, math::Size(), NULL);
scoped_refptr<PropertyListValue> transform_origin_list =
@@ -1391,9 +1529,12 @@
new PropertyListValue(transform_origin_builder.Pass()));
computed_style->set_transform_origin(transform_origin);
- scoped_refptr<const CSSComputedStyleData> parent_computed_style(
+ scoped_refptr<CSSComputedStyleData> parent_computed_style(
new CSSComputedStyleData());
- PromoteToComputedStyle(computed_style, parent_computed_style,
+ scoped_refptr<CSSComputedStyleDeclaration> parent_computed_style_declaration(
+ CreateComputedStyleDeclaration(parent_computed_style));
+
+ PromoteToComputedStyle(computed_style, parent_computed_style_declaration,
parent_computed_style, math::Size(), NULL);
scoped_refptr<PropertyListValue> transform_origin_list =
@@ -1435,9 +1576,12 @@
new PropertyListValue(transform_origin_builder.Pass()));
computed_style->set_transform_origin(transform_origin);
- scoped_refptr<const CSSComputedStyleData> parent_computed_style(
+ scoped_refptr<CSSComputedStyleData> parent_computed_style(
new CSSComputedStyleData());
- PromoteToComputedStyle(computed_style, parent_computed_style,
+ scoped_refptr<CSSComputedStyleDeclaration> parent_computed_style_declaration(
+ CreateComputedStyleDeclaration(parent_computed_style));
+
+ PromoteToComputedStyle(computed_style, parent_computed_style_declaration,
parent_computed_style, math::Size(), NULL);
scoped_refptr<PropertyListValue> transform_origin_list =
@@ -1479,9 +1623,12 @@
new PropertyListValue(transform_origin_builder.Pass()));
computed_style->set_transform_origin(transform_origin);
- scoped_refptr<const CSSComputedStyleData> parent_computed_style(
+ scoped_refptr<CSSComputedStyleData> parent_computed_style(
new CSSComputedStyleData());
- PromoteToComputedStyle(computed_style, parent_computed_style,
+ scoped_refptr<CSSComputedStyleDeclaration> parent_computed_style_declaration(
+ CreateComputedStyleDeclaration(parent_computed_style));
+
+ PromoteToComputedStyle(computed_style, parent_computed_style_declaration,
parent_computed_style, math::Size(), NULL);
scoped_refptr<PropertyListValue> transform_origin_list =
@@ -1523,9 +1670,12 @@
new PropertyListValue(transform_origin_builder.Pass()));
computed_style->set_transform_origin(transform_origin);
- scoped_refptr<const CSSComputedStyleData> parent_computed_style(
+ scoped_refptr<CSSComputedStyleData> parent_computed_style(
new CSSComputedStyleData());
- PromoteToComputedStyle(computed_style, parent_computed_style,
+ scoped_refptr<CSSComputedStyleDeclaration> parent_computed_style_declaration(
+ CreateComputedStyleDeclaration(parent_computed_style));
+
+ PromoteToComputedStyle(computed_style, parent_computed_style_declaration,
parent_computed_style, math::Size(), NULL);
scoped_refptr<PropertyListValue> transform_origin_list =
@@ -1568,9 +1718,12 @@
new PropertyListValue(transform_origin_builder.Pass()));
computed_style->set_transform_origin(transform_origin);
- scoped_refptr<const CSSComputedStyleData> parent_computed_style(
+ scoped_refptr<CSSComputedStyleData> parent_computed_style(
new CSSComputedStyleData());
- PromoteToComputedStyle(computed_style, parent_computed_style,
+ scoped_refptr<CSSComputedStyleDeclaration> parent_computed_style_declaration(
+ CreateComputedStyleDeclaration(parent_computed_style));
+
+ PromoteToComputedStyle(computed_style, parent_computed_style_declaration,
parent_computed_style, math::Size(), NULL);
scoped_refptr<PropertyListValue> transform_origin_list =
@@ -1614,7 +1767,10 @@
scoped_refptr<CSSComputedStyleData> parent_computed_style(
new CSSComputedStyleData());
parent_computed_style->set_font_size(new LengthValue(100, kPixelsUnit));
- PromoteToComputedStyle(computed_style, parent_computed_style,
+ scoped_refptr<CSSComputedStyleDeclaration> parent_computed_style_declaration(
+ CreateComputedStyleDeclaration(parent_computed_style));
+
+ PromoteToComputedStyle(computed_style, parent_computed_style_declaration,
parent_computed_style, math::Size(), NULL);
scoped_refptr<TransformFunctionListValue> computed_transform =
@@ -1631,5 +1787,238 @@
EXPECT_EQ(kPixelsUnit, computed_function->offset_as_length()->unit());
}
+TEST(PromoteToComputedStyle,
+ InheritedAnimatablePropertyShouldAlwaysBeDeclared) {
+ scoped_refptr<CSSComputedStyleData> computed_style(
+ new CSSComputedStyleData());
+
+ scoped_refptr<CSSComputedStyleData> parent_computed_style(
+ new CSSComputedStyleData());
+ parent_computed_style->set_color(RGBAColorValue::GetAqua());
+ scoped_refptr<CSSComputedStyleDeclaration> parent_computed_style_declaration(
+ CreateComputedStyleDeclaration(parent_computed_style));
+
+ // Verify that we're testing an inherited and animatable property.
+ ASSERT_TRUE(GetPropertyInheritance(kColorProperty) &&
+ GetPropertyAnimatable(kColorProperty));
+
+ // For each inherited, animatable property, the property value should be set
+ // to inherited if it is not already declared in PromoteToComputedStyle().
+ // This causes the value to be explicitly set within the CSSComputedStyleData
+ // and ensures that the original value will be available for transitions
+ // (which need to know the before and after state of the property) even when
+ // the property is inherited from a parent that has changed.
+ PromoteToComputedStyle(computed_style, parent_computed_style_declaration,
+ parent_computed_style, math::Size(), NULL);
+
+ // Verify that the color is declared in the child even though it was not
+ // explicitly declared.
+ ASSERT_TRUE(computed_style->IsDeclared(kColorProperty));
+}
+
+TEST(PromoteToComputedStyle,
+ DeclaredPropertiesInheritedFromParentShouldRemainValidWhenSetToSameValue) {
+ scoped_refptr<CSSComputedStyleData> computed_style(
+ new CSSComputedStyleData());
+
+ scoped_refptr<CSSComputedStyleData> parent_computed_style(
+ new CSSComputedStyleData());
+ parent_computed_style->set_color(
+ new RGBAColorValue(uint8(10), uint8(10), uint8(10), uint8(10)));
+ scoped_refptr<CSSComputedStyleDeclaration> parent_computed_style_declaration(
+ CreateComputedStyleDeclaration(parent_computed_style));
+
+ // Verify that we're testing an inherited and animatable property.
+ ASSERT_TRUE(GetPropertyInheritance(kColorProperty) &&
+ GetPropertyAnimatable(kColorProperty));
+
+ PromoteToComputedStyle(computed_style, parent_computed_style_declaration,
+ parent_computed_style, math::Size(), NULL);
+
+ // Verify that the declared properties inherited from the parent are valid.
+ ASSERT_TRUE(computed_style->AreDeclaredPropertiesInheritedFromParentValid());
+
+ parent_computed_style = new CSSComputedStyleData();
+ parent_computed_style->set_color(
+ new RGBAColorValue(uint8(10), uint8(10), uint8(10), uint8(10)));
+ parent_computed_style_declaration->SetData(parent_computed_style);
+
+ // Verify that the declared properties inherited from the parent are still
+ // valid.
+ ASSERT_TRUE(computed_style->AreDeclaredPropertiesInheritedFromParentValid());
+}
+
+TEST(PromoteToComputedStyle,
+ InheritedAnimatablePropertyShouldRetainValueAfterParentValueChanges) {
+ scoped_refptr<CSSComputedStyleData> computed_style(
+ new CSSComputedStyleData());
+
+ scoped_refptr<CSSComputedStyleData> parent_computed_style(
+ new CSSComputedStyleData());
+ parent_computed_style->set_color(RGBAColorValue::GetAqua());
+ scoped_refptr<CSSComputedStyleDeclaration> parent_computed_style_declaration(
+ CreateComputedStyleDeclaration(parent_computed_style));
+
+ // Verify that we're testing an inherited and animatable property.
+ ASSERT_TRUE(GetPropertyInheritance(kColorProperty) &&
+ GetPropertyAnimatable(kColorProperty));
+
+ PromoteToComputedStyle(computed_style, parent_computed_style_declaration,
+ parent_computed_style, math::Size(), NULL);
+
+ // Verify that the child's color is Aqua and matches the parent's color.
+ EXPECT_EQ(RGBAColorValue::GetAqua(), computed_style->color());
+ EXPECT_EQ(parent_computed_style->color(), computed_style->color());
+
+ // Verify that the declared properties inherited from the parent are valid.
+ ASSERT_TRUE(computed_style->AreDeclaredPropertiesInheritedFromParentValid());
+
+ parent_computed_style = new CSSComputedStyleData();
+ parent_computed_style->set_color(RGBAColorValue::GetNavy());
+ parent_computed_style_declaration->SetData(parent_computed_style);
+
+ // Verify that the color is still Aqua but that it no longer matches the
+ // parent's color.
+ EXPECT_EQ(RGBAColorValue::GetAqua(), computed_style->color());
+ EXPECT_NE(parent_computed_style->color(), computed_style->color());
+
+ // Verify that the declared properties inherited from the parent are no
+ // longer valid.
+ ASSERT_FALSE(computed_style->AreDeclaredPropertiesInheritedFromParentValid());
+}
+
+TEST(UpdateInheritedData,
+ UpdateInheritedDataShouldFixInheritedDataAfterItIsAdded) {
+ scoped_refptr<CSSComputedStyleData> grandparent_computed_style(
+ new CSSComputedStyleData());
+ scoped_refptr<CSSComputedStyleDeclaration>
+ grandparent_computed_style_declaration(
+ CreateComputedStyleDeclaration(grandparent_computed_style));
+
+ scoped_refptr<CSSComputedStyleData> parent_computed_style(
+ new CSSComputedStyleData());
+ // The parent should initially have the default value of normal.
+ EXPECT_EQ(FontStyleValue::GetNormal(), parent_computed_style->font_style());
+
+ PromoteToComputedStyle(parent_computed_style,
+ grandparent_computed_style_declaration,
+ grandparent_computed_style, math::Size(), NULL);
+ // The parent should still have the default value of normal.
+ EXPECT_EQ(FontStyleValue::GetNormal(), parent_computed_style->font_style());
+
+ scoped_refptr<CSSComputedStyleDeclaration> parent_computed_style_declaration(
+ CreateComputedStyleDeclaration(parent_computed_style));
+ scoped_refptr<CSSComputedStyleData> computed_style(
+ new CSSComputedStyleData());
+
+ PromoteToComputedStyle(computed_style, parent_computed_style_declaration,
+ grandparent_computed_style, math::Size(), NULL);
+
+ // The child should have the default value of normal.
+ EXPECT_EQ(FontStyleValue::GetNormal(), computed_style->font_style());
+
+ grandparent_computed_style = new CSSComputedStyleData();
+ grandparent_computed_style->set_font_style(FontStyleValue::GetOblique());
+ grandparent_computed_style_declaration->SetData(grandparent_computed_style);
+
+ // Even though the grandparent has changed, the child should have the original
+ // default value of normal until UpdateInheritedData() is called.
+ EXPECT_EQ(FontStyleValue::GetNormal(), computed_style->font_style());
+ parent_computed_style_declaration->UpdateInheritedData();
+
+ // Now that UpdateInheritedData() has been called, the child should have the
+ // new inherited value of oblique.
+ EXPECT_EQ(FontStyleValue::GetOblique(), computed_style->font_style());
+}
+
+TEST(UpdateInheritedData,
+ UpdateInheritedDataShouldFixInheritedDataAfterItIsRemoved) {
+ scoped_refptr<CSSComputedStyleData> grandparent_computed_style(
+ new CSSComputedStyleData());
+ grandparent_computed_style->set_font_style(FontStyleValue::GetItalic());
+ scoped_refptr<CSSComputedStyleDeclaration>
+ grandparent_computed_style_declaration(
+ CreateComputedStyleDeclaration(grandparent_computed_style));
+
+ scoped_refptr<CSSComputedStyleData> parent_computed_style(
+ new CSSComputedStyleData());
+ // The parent should initially have the default value of normal.
+ EXPECT_EQ(FontStyleValue::GetNormal(), parent_computed_style->font_style());
+
+ PromoteToComputedStyle(parent_computed_style,
+ grandparent_computed_style_declaration,
+ grandparent_computed_style, math::Size(), NULL);
+ // The parent should now have the inherited value of italic.
+ EXPECT_EQ(FontStyleValue::GetItalic(), parent_computed_style->font_style());
+
+ scoped_refptr<CSSComputedStyleDeclaration> parent_computed_style_declaration(
+ CreateComputedStyleDeclaration(parent_computed_style));
+ scoped_refptr<CSSComputedStyleData> computed_style(
+ new CSSComputedStyleData());
+
+ PromoteToComputedStyle(computed_style, parent_computed_style_declaration,
+ grandparent_computed_style, math::Size(), NULL);
+
+ // The child should have the inherited value of italic.
+ EXPECT_EQ(FontStyleValue::GetItalic(), computed_style->font_style());
+
+ grandparent_computed_style = new CSSComputedStyleData();
+ grandparent_computed_style_declaration->SetData(grandparent_computed_style);
+
+ // Even though the grandparent has changed, the child should have the original
+ // inherited value of italic until UpdateInheritedData() is called.
+ EXPECT_EQ(FontStyleValue::GetItalic(), computed_style->font_style());
+ parent_computed_style_declaration->UpdateInheritedData();
+
+ // Now that UpdateInheritedData() has been called, the child should have the
+ // default value of normal.
+ EXPECT_EQ(FontStyleValue::GetNormal(), computed_style->font_style());
+}
+
+TEST(UpdateInheritedData,
+ UpdateInheritedDataShouldFixInheritedDataAfterItChanges) {
+ scoped_refptr<CSSComputedStyleData> grandparent_computed_style(
+ new CSSComputedStyleData());
+ grandparent_computed_style->set_font_style(FontStyleValue::GetItalic());
+ scoped_refptr<CSSComputedStyleDeclaration>
+ grandparent_computed_style_declaration(
+ CreateComputedStyleDeclaration(grandparent_computed_style));
+
+ scoped_refptr<CSSComputedStyleData> parent_computed_style(
+ new CSSComputedStyleData());
+ // The parent should initially have the default value of normal.
+ EXPECT_EQ(FontStyleValue::GetNormal(), parent_computed_style->font_style());
+
+ PromoteToComputedStyle(parent_computed_style,
+ grandparent_computed_style_declaration,
+ grandparent_computed_style, math::Size(), NULL);
+ // The parent should now have the inherited value of italic.
+ EXPECT_EQ(FontStyleValue::GetItalic(), parent_computed_style->font_style());
+
+ scoped_refptr<CSSComputedStyleDeclaration> parent_computed_style_declaration(
+ CreateComputedStyleDeclaration(parent_computed_style));
+ scoped_refptr<CSSComputedStyleData> computed_style(
+ new CSSComputedStyleData());
+
+ PromoteToComputedStyle(computed_style, parent_computed_style_declaration,
+ grandparent_computed_style, math::Size(), NULL);
+
+ // The child should have the inherited value of italic.
+ EXPECT_EQ(FontStyleValue::GetItalic(), computed_style->font_style());
+
+ grandparent_computed_style = new CSSComputedStyleData();
+ grandparent_computed_style->set_font_style(FontStyleValue::GetOblique());
+ grandparent_computed_style_declaration->SetData(grandparent_computed_style);
+
+ // Even though the grandparent has changed, the child should have the original
+ // inherited value of italic until UpdateInheritedData() is called.
+ EXPECT_EQ(FontStyleValue::GetItalic(), computed_style->font_style());
+ parent_computed_style_declaration->UpdateInheritedData();
+
+ // Now that UpdateInheritedData() has been called, the child should have the
+ // new inherited value of oblique.
+ EXPECT_EQ(FontStyleValue::GetOblique(), computed_style->font_style());
+}
+
} // namespace cssom
} // namespace cobalt
diff --git a/src/cobalt/cssom/css_computed_style_data.cc b/src/cobalt/cssom/css_computed_style_data.cc
index c2a4689..590ea05 100644
--- a/src/cobalt/cssom/css_computed_style_data.cc
+++ b/src/cobalt/cssom/css_computed_style_data.cc
@@ -20,6 +20,7 @@
#include "base/lazy_instance.h"
#include "base/string_util.h"
+#include "cobalt/cssom/css_computed_style_declaration.h"
#include "cobalt/cssom/keyword_value.h"
#include "cobalt/cssom/length_value.h"
@@ -62,7 +63,9 @@
}
CSSComputedStyleData::CSSComputedStyleData()
- : has_inherited_properties_(false) {}
+ : has_declared_inherited_properties_(false) {}
+
+CSSComputedStyleData::~CSSComputedStyleData() {}
unsigned int CSSComputedStyleData::length() const {
// Computed style declarations have all known longhand properties.
@@ -79,12 +82,18 @@
DCHECK_GT(key, kNoneProperty);
DCHECK_LE(key, kMaxLonghandPropertyKey);
+ // If the property's value is explicitly declared, then simply return it.
if (declared_properties_[key]) {
return declared_property_values_.find(key)->second;
}
- if (ancestor_computed_style_ &&
- GetPropertyInheritance(key) == kInheritedYes) {
- return ancestor_computed_style_->GetPropertyValueReference(key);
+
+ // Otherwise, if the property is inherited and the parent has inherited
+ // properties, then retrieve the parent's value for the property.
+ if (parent_computed_style_declaration_ &&
+ GetPropertyInheritance(key) == kInheritedYes &&
+ parent_computed_style_declaration_->HasInheritedProperties()) {
+ return parent_computed_style_declaration_
+ ->GetInheritedPropertyValueReference(key);
}
// For the root element, which has no parent element, the inherited value is
@@ -270,8 +279,18 @@
if (value) {
declared_properties_.set(key, true);
declared_property_values_[key] = value;
- has_inherited_properties_ = has_inherited_properties_ ||
- GetPropertyInheritance(key) == kInheritedYes;
+ // Only set |has_declared_inherited_properties_| if the property is
+ // inherited and the the value isn't explicitly set to "inherit". If it is
+ // set to "inherit", then the value is simply a copy of the parent's value,
+ // which doesn't necessitate the node being included in the inheritance
+ // tree, as it doesn't provide new information.
+ // NOTE: Declaring a value of "inherit" on an inherited property is used for
+ // transitions, which need to know the original value of the property (which
+ // would otherwise be lost when the parent changed).
+ has_declared_inherited_properties_ =
+ has_declared_inherited_properties_ ||
+ (GetPropertyInheritance(key) == kInheritedYes &&
+ value != KeywordValue::GetInherit());
} else if (declared_properties_[key]) {
declared_properties_.set(key, false);
declared_property_values_.erase(key);
@@ -281,7 +300,10 @@
void CSSComputedStyleData::AssignFrom(const CSSComputedStyleData& rhs) {
declared_properties_ = rhs.declared_properties_;
declared_property_values_ = rhs.declared_property_values_;
- has_inherited_properties_ = rhs.has_inherited_properties_;
+ has_declared_inherited_properties_ = rhs.has_declared_inherited_properties_;
+ declared_properties_inherited_from_parent_ =
+ rhs.declared_properties_inherited_from_parent_;
+ parent_computed_style_declaration_ = rhs.parent_computed_style_declaration_;
}
std::string CSSComputedStyleData::SerializeCSSDeclarationBlock() const {
@@ -305,18 +327,84 @@
return serialized_text;
}
-void CSSComputedStyleData::SetParentComputedStyle(
- const scoped_refptr<const CSSComputedStyleData>& parent_computed_style) {
- if (parent_computed_style->has_inherited_properties_) {
- ancestor_computed_style_ = parent_computed_style;
- } else {
- // If the parent style does not have any inherited properties, we will never
- // need to refer to it for inherited properties, so we refer to the parent
- // style's ancestor instead. This gives the number of ancestor dereferences
- // needed to find the value of an inherited property an upper bound equal to
- // the total number of inheritable properties.
- ancestor_computed_style_ = parent_computed_style->ancestor_computed_style_;
+void CSSComputedStyleData::AddDeclaredPropertyInheritedFromParent(
+ PropertyKey key) {
+ declared_properties_inherited_from_parent_.push_back(key);
+}
+
+bool CSSComputedStyleData::AreDeclaredPropertiesInheritedFromParentValid()
+ const {
+ // If there are no declared properties inherited from the parent, then it's
+ // impossible for them to be invalid.
+ if (declared_properties_inherited_from_parent_.size() == 0) {
+ return true;
}
+
+ if (!parent_computed_style_declaration_) {
+ return false;
+ }
+
+ const scoped_refptr<const CSSComputedStyleData>& parent_computed_style_data =
+ parent_computed_style_declaration_->data();
+ if (!parent_computed_style_data) {
+ return false;
+ }
+
+ // Verify that the parent's data is valid.
+ DCHECK(parent_computed_style_data
+ ->AreDeclaredPropertiesInheritedFromParentValid());
+
+ // Walk the declared properties inherited from the parent. They're invalid if
+ // any no longer match the parent's value.
+ for (PropertyKeyVector::const_iterator iter =
+ declared_properties_inherited_from_parent_.begin();
+ iter != declared_properties_inherited_from_parent_.end(); ++iter) {
+ if (!GetPropertyValueReference(*iter)->Equals(
+ *parent_computed_style_data->GetPropertyValueReference(*iter))) {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool CSSComputedStyleData::DoDeclaredPropertiesMatch(
+ const scoped_refptr<const CSSComputedStyleData>& other) const {
+ // If the bitsets don't match, then there's no need to check the values;
+ // the declared properties are guaranteed to not match.
+ if (declared_properties_ != other->declared_properties_) {
+ return false;
+ }
+
+ // Verify that the same number of declared property values exist within the
+ // two CSSComputedStyleData objects. This should be guaranteed by the
+ // bitsets matching.
+ DCHECK_EQ(declared_property_values_.size(),
+ other->declared_property_values_.size());
+
+ // Walk the two lists of declared property values looking for any keys or
+ // values that don't match.
+ PropertyValues::const_iterator iter1 = declared_property_values_.begin();
+ PropertyValues::const_iterator iter2 =
+ other->declared_property_values_.begin();
+ for (; iter1 != declared_property_values_.end(); ++iter1, ++iter2) {
+ if (iter1->first != iter2->first ||
+ !iter1->second->Equals(*iter2->second)) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+void CSSComputedStyleData::SetParentComputedStyleDeclaration(
+ const scoped_refptr<CSSComputedStyleDeclaration>&
+ parent_computed_style_declaration) {
+ parent_computed_style_declaration_ = parent_computed_style_declaration;
+}
+
+const scoped_refptr<CSSComputedStyleDeclaration>&
+CSSComputedStyleData::GetParentComputedStyleDeclaration() const {
+ return parent_computed_style_declaration_;
}
} // namespace cssom
diff --git a/src/cobalt/cssom/css_computed_style_data.h b/src/cobalt/cssom/css_computed_style_data.h
index 80c93b7..e303868 100644
--- a/src/cobalt/cssom/css_computed_style_data.h
+++ b/src/cobalt/cssom/css_computed_style_data.h
@@ -31,12 +31,11 @@
namespace cobalt {
namespace cssom {
+class CSSComputedStyleDeclaration;
+
// CSSComputedStyleData which has PropertyValue type properties only used
-// internally and it is not exposed to JavaScript. It derives from
-// RefCountedThreadSafe instead of RefCounted so that it can be passed forward
-// to another thread for animating before rendering a scene.
-class CSSComputedStyleData
- : public base::RefCountedThreadSafe<CSSComputedStyleData> {
+// internally and it is not exposed to JavaScript.
+class CSSComputedStyleData : public base::RefCounted<CSSComputedStyleData> {
public:
// This class provides the ability to determine whether the properties of two
// CSSComputedStyleData objects match for a given set of property keys.
@@ -61,6 +60,7 @@
16, std::equal_to<PropertyKey> > PropertyValues;
CSSComputedStyleData();
+ ~CSSComputedStyleData();
// The length attribute must return the number of CSS declarations in the
// declarations.
@@ -661,25 +661,54 @@
void AssignFrom(const CSSComputedStyleData& rhs);
+ // This returns the result of serializing a CSS declaration block.
+ // The current implementation does not handle shorthands.
+ // https://www.w3.org/TR/cssom/#serialize-a-css-declaration-block
+ std::string SerializeCSSDeclarationBlock() const;
+
// Returns true if the property is explicitly declared in this style, as
// opposed to implicitly inheriting from its parent or the initial value.
bool IsDeclared(const PropertyKey key) const {
return declared_properties_[key];
}
- // This returns the result of serializing a CSS declaration block.
- // The current implementation does not handle shorthands.
- // https://www.w3.org/TR/cssom/#serialize-a-css-declaration-block
- std::string SerializeCSSDeclarationBlock() const;
+ // Whether or not any inherited properties have been declared.
+ // NOTE: Inherited properties that are set to a value "inherit" do not impact
+ // this flag, as they will have the same value as the parent and can be
+ // skipped by descendants retrieving their inherited value without impacting
+ // the returned value.
+ bool has_declared_inherited_properties() const {
+ return has_declared_inherited_properties_;
+ }
- // Set the parent computed style for tracking inherited properties.
- void SetParentComputedStyle(
- const scoped_refptr<const CSSComputedStyleData>& parent_computed_style);
+ // Adds a declared property that was inherited from the parent to an
+ // internal list. This facilitates tracking of whether or not a value that was
+ // initially set to a parent's value continues to match the parent's value.
+ void AddDeclaredPropertyInheritedFromParent(PropertyKey key);
+
+ // Returns true if all of the declared properties that were inherited from the
+ // parent are still valid. They become invalid when the parent's value
+ // changes.
+ bool AreDeclaredPropertiesInheritedFromParentValid() const;
PropertyValues* declared_property_values() {
return &declared_property_values_;
}
+ // Returns whether or not the declared properties in the passed in
+ // CSSComputedStyleData matches those declared within this one.
+ bool DoDeclaredPropertiesMatch(
+ const scoped_refptr<const CSSComputedStyleData>& other) const;
+
+ // Set the parent computed style for tracking inherited properties.
+ void SetParentComputedStyleDeclaration(
+ const scoped_refptr<CSSComputedStyleDeclaration>&
+ parent_computed_style_declaration);
+
+ // Returns the parent computed style used for tracking inherited properties.
+ const scoped_refptr<CSSComputedStyleDeclaration>&
+ GetParentComputedStyleDeclaration() const;
+
private:
// Helper function that returns the computed value if the initial property
// value is not computed or returns the initial value if it is computed.
@@ -691,10 +720,25 @@
LonghandPropertiesBitset declared_properties_;
PropertyValues declared_property_values_;
- scoped_refptr<const CSSComputedStyleData> ancestor_computed_style_;
+ // True if this style has any inherited properties declared.
+ // NOTE: Inherited properties that are set to a value "inherit" do not impact
+ // this flag, as they will have the same value as the parent and can be
+ // skipped by descendants retrieving their inherited value without impacting
+ // the returned value.
+ bool has_declared_inherited_properties_;
- // True if this style has any inheritable properties defined.
- bool has_inherited_properties_;
+ // Properties that were initially set to a value of "inherit" before being
+ // updated with the parent's value. This is used to determine whether the
+ // declared properties inherited from the parent have subsequently changed.
+ PropertyKeyVector declared_properties_inherited_from_parent_;
+
+ // The parent used for inherited properties.
+ // NOTE: The parent is a CSSComputedStyleDeclaration, rather than a
+ // CSSComputedStyleData, in order to allow for the replacement of ancestor
+ // CSSComputedStyleData objects without requiring all of its descendants to
+ // also be replaced. The descendant's inherited property value will instead
+ // dynamically update.
+ scoped_refptr<CSSComputedStyleDeclaration> parent_computed_style_declaration_;
};
} // namespace cssom
diff --git a/src/cobalt/cssom/css_computed_style_data_test.cc b/src/cobalt/cssom/css_computed_style_data_test.cc
index 3dd7f71..2fcb1ea 100644
--- a/src/cobalt/cssom/css_computed_style_data_test.cc
+++ b/src/cobalt/cssom/css_computed_style_data_test.cc
@@ -1128,5 +1128,68 @@
EXPECT_EQ(KeywordValue::GetBlock(), style->display());
}
+TEST(CSSComputedStyleDataTest,
+ DoDeclaredPropertiesMatchWorksWithUnequalNumberOfDeclaredProperties) {
+ scoped_refptr<CSSComputedStyleData> style1 = new CSSComputedStyleData();
+ style1->set_font_size(new LengthValue(50, kPixelsUnit));
+
+ scoped_refptr<CSSComputedStyleData> style2 = new CSSComputedStyleData();
+
+ ASSERT_FALSE(style1->DoDeclaredPropertiesMatch(style2));
+ ASSERT_FALSE(style2->DoDeclaredPropertiesMatch(style1));
+}
+
+TEST(CSSComputedStyleDataTest,
+ DoDeclaredPropertiesMatchWorksWithSingleUnequalProperty) {
+ scoped_refptr<CSSComputedStyleData> style1 = new CSSComputedStyleData();
+ style1->set_font_size(new LengthValue(50, kPixelsUnit));
+
+ scoped_refptr<CSSComputedStyleData> style2 = new CSSComputedStyleData();
+ style2->set_font_size(new LengthValue(30, kPixelsUnit));
+
+ ASSERT_FALSE(style1->DoDeclaredPropertiesMatch(style2));
+ ASSERT_FALSE(style2->DoDeclaredPropertiesMatch(style1));
+}
+
+TEST(CSSComputedStyleDataTest,
+ DoDeclaredPropertiesMatchWorksWithSingleEqualProperty) {
+ scoped_refptr<CSSComputedStyleData> style1 = new CSSComputedStyleData();
+ style1->set_font_size(new LengthValue(50, kPixelsUnit));
+
+ scoped_refptr<CSSComputedStyleData> style2 = new CSSComputedStyleData();
+ style2->set_font_size(new LengthValue(50, kPixelsUnit));
+
+ ASSERT_TRUE(style1->DoDeclaredPropertiesMatch(style2));
+ ASSERT_TRUE(style2->DoDeclaredPropertiesMatch(style1));
+}
+
+TEST(CSSComputedStyleDataTest,
+ DoDeclaredPropertiesMatchWorksWithMultipleUnequalProperties) {
+ scoped_refptr<CSSComputedStyleData> style1 = new CSSComputedStyleData();
+ style1->set_position(KeywordValue::GetAbsolute());
+ style1->set_font_size(new LengthValue(50, kPixelsUnit));
+
+ scoped_refptr<CSSComputedStyleData> style2 = new CSSComputedStyleData();
+ style2->set_position(KeywordValue::GetAbsolute());
+ style2->set_font_size(new LengthValue(30, kPixelsUnit));
+
+ ASSERT_FALSE(style1->DoDeclaredPropertiesMatch(style2));
+ ASSERT_FALSE(style2->DoDeclaredPropertiesMatch(style1));
+}
+
+TEST(CSSComputedStyleDataTest,
+ DoDeclaredPropertiesMatchWorksWithMultipleEqualProperty) {
+ scoped_refptr<CSSComputedStyleData> style1 = new CSSComputedStyleData();
+ style1->set_position(KeywordValue::GetAbsolute());
+ style1->set_font_size(new LengthValue(50, kPixelsUnit));
+
+ scoped_refptr<CSSComputedStyleData> style2 = new CSSComputedStyleData();
+ style2->set_position(KeywordValue::GetAbsolute());
+ style2->set_font_size(new LengthValue(50, kPixelsUnit));
+
+ ASSERT_TRUE(style1->DoDeclaredPropertiesMatch(style2));
+ ASSERT_TRUE(style2->DoDeclaredPropertiesMatch(style1));
+}
+
} // namespace cssom
} // namespace cobalt
diff --git a/src/cobalt/cssom/css_computed_style_declaration.cc b/src/cobalt/cssom/css_computed_style_declaration.cc
index 0d477a4..11c7dbb 100644
--- a/src/cobalt/cssom/css_computed_style_declaration.cc
+++ b/src/cobalt/cssom/css_computed_style_declaration.cc
@@ -72,5 +72,45 @@
exception_state);
}
+void CSSComputedStyleDeclaration::SetData(
+ const scoped_refptr<const CSSComputedStyleData>& data) {
+ data_ = data;
+ // After setting |data_|, |data_with_inherited_properties_| needs to be
+ // updated. It may have changed.
+ UpdateInheritedData();
+}
+
+void CSSComputedStyleDeclaration::UpdateInheritedData() {
+ if (!data_) {
+ // If there's no data, then there can be no data with inherited properties.
+ data_with_inherited_properties_ = NULL;
+ } else if (data_->has_declared_inherited_properties()) {
+ // Otherwise, if the data has inherited properties, then it's also the first
+ // data with inherited properties.
+ data_with_inherited_properties_ = data_;
+ } else {
+ // Otherwise, |data_with_inherited_properties_| should be set to the parent
+ // computed style's |data_with_inherited_properties_|. This is because the
+ // updates always cascade down the tree and the parent is guaranteed to
+ // have already been updated when the child is updated.
+ const scoped_refptr<CSSComputedStyleDeclaration>&
+ parent_computed_style_declaration =
+ data_->GetParentComputedStyleDeclaration();
+ if (parent_computed_style_declaration) {
+ data_with_inherited_properties_ =
+ parent_computed_style_declaration->data_with_inherited_properties_;
+ } else {
+ data_with_inherited_properties_ = NULL;
+ }
+ }
+}
+
+const scoped_refptr<PropertyValue>&
+CSSComputedStyleDeclaration::GetInheritedPropertyValueReference(
+ PropertyKey key) const {
+ DCHECK(data_with_inherited_properties_);
+ return data_with_inherited_properties_->GetPropertyValueReference(key);
+}
+
} // namespace cssom
} // namespace cobalt
diff --git a/src/cobalt/cssom/css_computed_style_declaration.h b/src/cobalt/cssom/css_computed_style_declaration.h
index 36a4947..e166979 100644
--- a/src/cobalt/cssom/css_computed_style_declaration.h
+++ b/src/cobalt/cssom/css_computed_style_declaration.h
@@ -58,10 +58,23 @@
const scoped_refptr<const CSSComputedStyleData>& data() const {
return data_;
}
- void set_data(const scoped_refptr<const CSSComputedStyleData>& data) {
- data_ = data;
+ void SetData(const scoped_refptr<const CSSComputedStyleData>& data);
+
+ // Updates the pointer to the nearest CSSComputedStyleData ancestor,
+ // inclusive, which has inherited properties declared.
+ void UpdateInheritedData();
+
+ // Returns whether or not this object or any ancestors have inherited
+ // properties declared.
+ bool HasInheritedProperties() const {
+ return data_with_inherited_properties_ != NULL;
}
+ // Returns the reference to the property value for an inherited property.
+ // Should only be called if HasInheritedProperties() returns true.
+ const scoped_refptr<PropertyValue>& GetInheritedPropertyValueReference(
+ PropertyKey key) const;
+
const scoped_refptr<const web_animations::AnimationSet>& animations() const {
return animations_;
}
@@ -74,9 +87,15 @@
// From CSSStyleDeclaration.
std::string GetDeclaredPropertyValueStringByKey(
const PropertyKey key) const OVERRIDE;
+
+ // The CSSComputedStyleData owned by this object.
scoped_refptr<const CSSComputedStyleData> data_;
- // All animation that applies to the above computed style.
+ // The nearest CSSComputedStyleData ancestor, inclusive, which has inherited
+ // properties declared.
+ scoped_refptr<const CSSComputedStyleData> data_with_inherited_properties_;
+
+ // All animation that applies to the above computed style.
scoped_refptr<const web_animations::AnimationSet> animations_;
DISALLOW_COPY_AND_ASSIGN(CSSComputedStyleDeclaration);
diff --git a/src/cobalt/cssom/css_transition_set.cc b/src/cobalt/cssom/css_transition_set.cc
index 4292a94..6edeae6 100644
--- a/src/cobalt/cssom/css_transition_set.cc
+++ b/src/cobalt/cssom/css_transition_set.cc
@@ -84,10 +84,8 @@
// For each animatable property, check to see if there are any transitions
// assigned to it. If so, check to see if there are any existing transitions
// that must be updated, otherwise introduce new transitions.
- const AnimatablePropertyList& animatable_properties =
- GetAnimatableProperties();
- for (AnimatablePropertyList::const_iterator iter =
- animatable_properties.begin();
+ const PropertyKeyVector& animatable_properties = GetAnimatableProperties();
+ for (PropertyKeyVector::const_iterator iter = animatable_properties.begin();
iter != animatable_properties.end(); ++iter) {
UpdateTransitionForProperty(
*iter, current_time, source_computed_style.GetPropertyValue(*iter),
@@ -216,7 +214,7 @@
if (existing_transition &&
current_time < existing_transition->EndTime()) {
- // A transition is already ocurring, so we handle this case a bit
+ // A transition is already occurring, so we handle this case a bit
// differently depending on if we're reversing the previous transition
// or starting a completely different one.
transitions_.UpdateTransitionForProperty(
diff --git a/src/cobalt/cssom/cssom.gyp b/src/cobalt/cssom/cssom.gyp
index ab8852c..63be9ea 100644
--- a/src/cobalt/cssom/cssom.gyp
+++ b/src/cobalt/cssom/cssom.gyp
@@ -227,6 +227,7 @@
],
'dependencies': [
'<(DEPTH)/cobalt/base/base.gyp:base',
+ '<(DEPTH)/cobalt/dom/dom_exception.gyp:dom_exception',
'<(DEPTH)/cobalt/math/math.gyp:math',
'<(DEPTH)/googleurl/googleurl.gyp:googleurl',
'embed_resources_as_header_files',
diff --git a/src/cobalt/cssom/property_definitions.cc b/src/cobalt/cssom/property_definitions.cc
index d589181..8133992 100644
--- a/src/cobalt/cssom/property_definitions.cc
+++ b/src/cobalt/cssom/property_definitions.cc
@@ -49,6 +49,7 @@
: name(NULL),
inherited(kInheritedNo),
animatable(kAnimatableNo),
+ impacts_child_declared_style(kImpactsChildDeclaredStyleNo),
impacts_box_generation(kImpactsBoxGenerationNo),
impacts_box_sizes(kImpactsBoxSizesNo),
impacts_box_cross_references(kImpactsBoxCrossReferencesNo) {}
@@ -56,6 +57,7 @@
const char* name;
Inherited inherited;
Animatable animatable;
+ ImpactsChildDeclaredStyle impacts_child_declared_style;
ImpactsBoxGeneration impacts_box_generation;
ImpactsBoxSizes impacts_box_sizes;
ImpactsBoxCrossReferences impacts_box_cross_references;
@@ -68,11 +70,14 @@
std::vector<PropertyKey> lexicographical_longhand_keys;
PropertyDefinition properties[kMaxEveryPropertyKey + 1];
- AnimatablePropertyList animatable_properties;
+ PropertyKeyVector animatable_properties;
+ PropertyKeyVector inherited_animatable_properties;
void SetPropertyDefinition(
PropertyKey key, const char* name, Inherited inherited,
- Animatable animatable, ImpactsBoxGeneration impacts_box_generation,
+ Animatable animatable,
+ ImpactsChildDeclaredStyle impacts_child_declared_style,
+ ImpactsBoxGeneration impacts_box_generation,
ImpactsBoxSizes impacts_box_sizes,
ImpactsBoxCrossReferences impacts_box_cross_references,
const scoped_refptr<PropertyValue>& initial_value) {
@@ -82,6 +87,7 @@
definition.name = name;
definition.inherited = inherited;
definition.animatable = animatable;
+ definition.impacts_child_declared_style = impacts_child_declared_style;
definition.impacts_box_generation = impacts_box_generation;
definition.impacts_box_sizes = impacts_box_sizes;
definition.impacts_box_cross_references = impacts_box_cross_references;
@@ -151,61 +157,65 @@
NonTrivialGlobalVariables::NonTrivialGlobalVariables() {
// https://www.w3.org/TR/css3-animations/#animation-delay-property
- SetPropertyDefinition(kAnimationDelayProperty, "animation-delay",
- kInheritedNo, kAnimatableNo, kImpactsBoxGenerationNo,
- kImpactsBoxSizesNo, kImpactsBoxCrossReferencesNo,
- CreateTimeListWithZeroSeconds());
+ SetPropertyDefinition(
+ kAnimationDelayProperty, "animation-delay", kInheritedNo, kAnimatableNo,
+ kImpactsChildDeclaredStyleNo, kImpactsBoxGenerationNo, kImpactsBoxSizesNo,
+ kImpactsBoxCrossReferencesNo, CreateTimeListWithZeroSeconds());
// https://www.w3.org/TR/css3-animations/#animation-direction-property
SetPropertyDefinition(
kAnimationDirectionProperty, "animation-direction", kInheritedNo,
- kAnimatableNo, kImpactsBoxGenerationNo, kImpactsBoxSizesNo,
- kImpactsBoxCrossReferencesNo,
+ kAnimatableNo, kImpactsChildDeclaredStyleNo, kImpactsBoxGenerationNo,
+ kImpactsBoxSizesNo, kImpactsBoxCrossReferencesNo,
CreateSinglePropertyListWithValue(KeywordValue::GetNormal()));
// https://www.w3.org/TR/css3-animations/#animation-duration-property
SetPropertyDefinition(kAnimationDurationProperty, "animation-duration",
- kInheritedNo, kAnimatableNo, kImpactsBoxGenerationNo,
+ kInheritedNo, kAnimatableNo,
+ kImpactsChildDeclaredStyleNo, kImpactsBoxGenerationNo,
kImpactsBoxSizesNo, kImpactsBoxCrossReferencesNo,
CreateTimeListWithZeroSeconds());
// https://www.w3.org/TR/css3-animations/#animation-fill-mode-property
SetPropertyDefinition(
kAnimationFillModeProperty, "animation-fill-mode", kInheritedNo,
- kAnimatableNo, kImpactsBoxGenerationNo, kImpactsBoxSizesNo,
- kImpactsBoxCrossReferencesNo,
+ kAnimatableNo, kImpactsChildDeclaredStyleNo, kImpactsBoxGenerationNo,
+ kImpactsBoxSizesNo, kImpactsBoxCrossReferencesNo,
CreateSinglePropertyListWithValue(KeywordValue::GetNone()));
// https://www.w3.org/TR/css3-animations/#animation-iteration-count-property
SetPropertyDefinition(
kAnimationIterationCountProperty, "animation-iteration-count",
- kInheritedNo, kAnimatableNo, kImpactsBoxGenerationNo, kImpactsBoxSizesNo,
- kImpactsBoxCrossReferencesNo,
+ kInheritedNo, kAnimatableNo, kImpactsChildDeclaredStyleNo,
+ kImpactsBoxGenerationNo, kImpactsBoxSizesNo, kImpactsBoxCrossReferencesNo,
CreateSinglePropertyListWithValue(new NumberValue(1.0f)));
// https://www.w3.org/TR/css3-animations/#animation-name-property
SetPropertyDefinition(
kAnimationNameProperty, "animation-name", kInheritedNo, kAnimatableNo,
- kImpactsBoxGenerationNo, kImpactsBoxSizesNo, kImpactsBoxCrossReferencesNo,
+ kImpactsChildDeclaredStyleNo, kImpactsBoxGenerationNo, kImpactsBoxSizesNo,
+ kImpactsBoxCrossReferencesNo,
CreateSinglePropertyListWithValue(KeywordValue::GetNone()));
// https://www.w3.org/TR/css3-animations/#animation-timing-function-property
- SetPropertyDefinition(kAnimationTimingFunctionProperty,
- "animation-timing-function", kInheritedNo,
- kAnimatableNo, kImpactsBoxGenerationNo,
- kImpactsBoxSizesNo, kImpactsBoxCrossReferencesNo,
- CreateTransitionTimingFunctionListWithEase());
+ SetPropertyDefinition(
+ kAnimationTimingFunctionProperty, "animation-timing-function",
+ kInheritedNo, kAnimatableNo, kImpactsChildDeclaredStyleNo,
+ kImpactsBoxGenerationNo, kImpactsBoxSizesNo, kImpactsBoxCrossReferencesNo,
+ CreateTransitionTimingFunctionListWithEase());
// https://www.w3.org/TR/css3-background/#the-background-color
SetPropertyDefinition(kBackgroundColorProperty, "background-color",
- kInheritedNo, kAnimatableYes, kImpactsBoxGenerationNo,
+ kInheritedNo, kAnimatableYes,
+ kImpactsChildDeclaredStyleNo, kImpactsBoxGenerationNo,
kImpactsBoxSizesNo, kImpactsBoxCrossReferencesNo,
new RGBAColorValue(0x00000000));
// https://www.w3.org/TR/css3-background/#background-image
SetPropertyDefinition(
kBackgroundImageProperty, "background-image", kInheritedNo, kAnimatableNo,
- kImpactsBoxGenerationNo, kImpactsBoxSizesNo, kImpactsBoxCrossReferencesNo,
+ kImpactsChildDeclaredStyleNo, kImpactsBoxGenerationNo, kImpactsBoxSizesNo,
+ kImpactsBoxCrossReferencesNo,
CreateSinglePropertyListWithValue(KeywordValue::GetNone()));
// https://www.w3.org/TR/css3-background/#the-background-position
@@ -219,7 +229,8 @@
scoped_refptr<PropertyListValue> background_position_list(
new PropertyListValue(background_position_builder.Pass()));
SetPropertyDefinition(kBackgroundPositionProperty, "background-position",
- kInheritedNo, kAnimatableNo, kImpactsBoxGenerationNo,
+ kInheritedNo, kAnimatableNo,
+ kImpactsChildDeclaredStyleNo, kImpactsBoxGenerationNo,
kImpactsBoxSizesNo, kImpactsBoxCrossReferencesNo,
background_position_list);
@@ -234,10 +245,10 @@
background_repeat_builder->push_back(KeywordValue::GetRepeat());
scoped_refptr<PropertyListValue> background_repeat_list(
new PropertyListValue(background_repeat_builder.Pass()));
- SetPropertyDefinition(kBackgroundRepeatProperty, "background-repeat",
- kInheritedNo, kAnimatableNo, kImpactsBoxGenerationNo,
- kImpactsBoxSizesNo, kImpactsBoxCrossReferencesNo,
- background_repeat_list);
+ SetPropertyDefinition(
+ kBackgroundRepeatProperty, "background-repeat", kInheritedNo,
+ kAnimatableNo, kImpactsChildDeclaredStyleNo, kImpactsBoxGenerationNo,
+ kImpactsBoxSizesNo, kImpactsBoxCrossReferencesNo, background_repeat_list);
// The first value gives the width of the corresponding image, and the second
// value gives its height. If only one value is given, the second is assumed
@@ -250,52 +261,59 @@
background_size_builder->push_back(KeywordValue::GetAuto());
scoped_refptr<PropertyListValue> background_size_list(
new PropertyListValue(background_size_builder.Pass()));
- SetPropertyDefinition(kBackgroundSizeProperty, "background-size",
- kInheritedNo, kAnimatableNo, kImpactsBoxGenerationNo,
- kImpactsBoxSizesNo, kImpactsBoxCrossReferencesNo,
- background_size_list);
+ SetPropertyDefinition(
+ kBackgroundSizeProperty, "background-size", kInheritedNo, kAnimatableNo,
+ kImpactsChildDeclaredStyleNo, kImpactsBoxGenerationNo, kImpactsBoxSizesNo,
+ kImpactsBoxCrossReferencesNo, background_size_list);
// This sets the foreground color of the border specified by the border-style
// property.
// https://www.w3.org/TR/css3-background/#border-color
- SetPropertyDefinition(kBorderTopColorProperty, "border-top-color",
- kInheritedNo, kAnimatableYes, kImpactsBoxGenerationNo,
- kImpactsBoxSizesNo, kImpactsBoxCrossReferencesNo,
- KeywordValue::GetCurrentColor());
+ SetPropertyDefinition(
+ kBorderTopColorProperty, "border-top-color", kInheritedNo, kAnimatableYes,
+ kImpactsChildDeclaredStyleNo, kImpactsBoxGenerationNo, kImpactsBoxSizesNo,
+ kImpactsBoxCrossReferencesNo, KeywordValue::GetCurrentColor());
SetPropertyDefinition(kBorderRightColorProperty, "border-right-color",
- kInheritedNo, kAnimatableYes, kImpactsBoxGenerationNo,
+ kInheritedNo, kAnimatableYes,
+ kImpactsChildDeclaredStyleNo, kImpactsBoxGenerationNo,
kImpactsBoxSizesNo, kImpactsBoxCrossReferencesNo,
KeywordValue::GetCurrentColor());
SetPropertyDefinition(kBorderBottomColorProperty, "border-bottom-color",
- kInheritedNo, kAnimatableYes, kImpactsBoxGenerationNo,
+ kInheritedNo, kAnimatableYes,
+ kImpactsChildDeclaredStyleNo, kImpactsBoxGenerationNo,
kImpactsBoxSizesNo, kImpactsBoxCrossReferencesNo,
KeywordValue::GetCurrentColor());
SetPropertyDefinition(kBorderLeftColorProperty, "border-left-color",
- kInheritedNo, kAnimatableYes, kImpactsBoxGenerationNo,
+ kInheritedNo, kAnimatableYes,
+ kImpactsChildDeclaredStyleNo, kImpactsBoxGenerationNo,
kImpactsBoxSizesNo, kImpactsBoxCrossReferencesNo,
KeywordValue::GetCurrentColor());
// https://www.w3.org/TR/css3-background/#border-style
SetPropertyDefinition(kBorderTopStyleProperty, "border-top-style",
- kInheritedNo, kAnimatableNo, kImpactsBoxGenerationNo,
+ kInheritedNo, kAnimatableNo,
+ kImpactsChildDeclaredStyleNo, kImpactsBoxGenerationNo,
kImpactsBoxSizesYes, kImpactsBoxCrossReferencesNo,
KeywordValue::GetNone());
SetPropertyDefinition(kBorderRightStyleProperty, "border-right-style",
- kInheritedNo, kAnimatableNo, kImpactsBoxGenerationNo,
+ kInheritedNo, kAnimatableNo,
+ kImpactsChildDeclaredStyleNo, kImpactsBoxGenerationNo,
kImpactsBoxSizesYes, kImpactsBoxCrossReferencesNo,
KeywordValue::GetNone());
SetPropertyDefinition(kBorderBottomStyleProperty, "border-bottom-style",
- kInheritedNo, kAnimatableNo, kImpactsBoxGenerationNo,
+ kInheritedNo, kAnimatableNo,
+ kImpactsChildDeclaredStyleNo, kImpactsBoxGenerationNo,
kImpactsBoxSizesYes, kImpactsBoxCrossReferencesNo,
KeywordValue::GetNone());
SetPropertyDefinition(kBorderLeftStyleProperty, "border-left-style",
- kInheritedNo, kAnimatableNo, kImpactsBoxGenerationNo,
+ kInheritedNo, kAnimatableNo,
+ kImpactsChildDeclaredStyleNo, kImpactsBoxGenerationNo,
kImpactsBoxSizesYes, kImpactsBoxCrossReferencesNo,
KeywordValue::GetNone());
@@ -305,259 +323,290 @@
// 'medium' font size is 17 px or less.
// https://www.w3.org/TR/css3-background/#border-width
SetPropertyDefinition(kBorderTopWidthProperty, "border-top-width",
- kInheritedNo, kAnimatableNo, kImpactsBoxGenerationNo,
+ kInheritedNo, kAnimatableNo,
+ kImpactsChildDeclaredStyleNo, kImpactsBoxGenerationNo,
kImpactsBoxSizesYes, kImpactsBoxCrossReferencesNo,
new LengthValue(3, kPixelsUnit));
SetPropertyDefinition(kBorderRightWidthProperty, "border-right-width",
- kInheritedNo, kAnimatableNo, kImpactsBoxGenerationNo,
+ kInheritedNo, kAnimatableNo,
+ kImpactsChildDeclaredStyleNo, kImpactsBoxGenerationNo,
kImpactsBoxSizesYes, kImpactsBoxCrossReferencesNo,
new LengthValue(3, kPixelsUnit));
SetPropertyDefinition(kBorderBottomWidthProperty, "border-bottom-width",
- kInheritedNo, kAnimatableNo, kImpactsBoxGenerationNo,
+ kInheritedNo, kAnimatableNo,
+ kImpactsChildDeclaredStyleNo, kImpactsBoxGenerationNo,
kImpactsBoxSizesYes, kImpactsBoxCrossReferencesNo,
new LengthValue(3, kPixelsUnit));
SetPropertyDefinition(kBorderLeftWidthProperty, "border-left-width",
- kInheritedNo, kAnimatableNo, kImpactsBoxGenerationNo,
+ kInheritedNo, kAnimatableNo,
+ kImpactsChildDeclaredStyleNo, kImpactsBoxGenerationNo,
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(kBorderRadiusProperty, "border-radius", kInheritedNo,
- kAnimatableNo, kImpactsBoxGenerationNo,
- kImpactsBoxSizesNo, kImpactsBoxCrossReferencesNo,
- new LengthValue(0, kPixelsUnit));
+ SetPropertyDefinition(
+ kBorderRadiusProperty, "border-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,
- kImpactsBoxGenerationNo, kImpactsBoxSizesYes,
- kImpactsBoxCrossReferencesNo, KeywordValue::GetAuto());
+ kImpactsChildDeclaredStyleNo, kImpactsBoxGenerationNo,
+ kImpactsBoxSizesYes, kImpactsBoxCrossReferencesNo,
+ KeywordValue::GetAuto());
// https://www.w3.org/TR/css3-background/#the-box-shadow
SetPropertyDefinition(kBoxShadowProperty, "box-shadow", kInheritedNo,
- kAnimatableNo, kImpactsBoxGenerationNo,
- kImpactsBoxSizesNo, kImpactsBoxCrossReferencesNo,
- KeywordValue::GetNone());
+ kAnimatableNo, kImpactsChildDeclaredStyleNo,
+ kImpactsBoxGenerationNo, kImpactsBoxSizesNo,
+ kImpactsBoxCrossReferencesNo, KeywordValue::GetNone());
// Opaque black in Chromium and Cobalt.
// https://www.w3.org/TR/css3-color/#foreground
SetPropertyDefinition(kColorProperty, "color", kInheritedYes, kAnimatableYes,
- kImpactsBoxGenerationYes, kImpactsBoxSizesNo,
- kImpactsBoxCrossReferencesNo,
+ kImpactsChildDeclaredStyleYes, kImpactsBoxGenerationYes,
+ kImpactsBoxSizesNo, kImpactsBoxCrossReferencesNo,
new RGBAColorValue(0x000000ff));
// https://www.w3.org/TR/CSS21/generate.html#content
SetPropertyDefinition(kContentProperty, "content", kInheritedNo,
- kAnimatableNo, kImpactsBoxGenerationYes,
- kImpactsBoxSizesNo, kImpactsBoxCrossReferencesNo,
+ kAnimatableNo, kImpactsChildDeclaredStyleNo,
+ kImpactsBoxGenerationYes, kImpactsBoxSizesNo,
+ kImpactsBoxCrossReferencesNo,
KeywordValue::GetNormal());
// https://www.w3.org/TR/CSS21/visuren.html#display-prop
SetPropertyDefinition(kDisplayProperty, "display", kInheritedNo,
- kAnimatableNo, kImpactsBoxGenerationYes,
- kImpactsBoxSizesNo, kImpactsBoxCrossReferencesNo,
+ kAnimatableNo, kImpactsChildDeclaredStyleNo,
+ kImpactsBoxGenerationYes, kImpactsBoxSizesNo,
+ kImpactsBoxCrossReferencesNo,
KeywordValue::GetInline());
// Varies by platform in Chromium, Roboto in Cobalt.
// https://www.w3.org/TR/css3-fonts/#font-family-prop
SetPropertyDefinition(
kFontFamilyProperty, "font-family", kInheritedYes, kAnimatableNo,
- kImpactsBoxGenerationYes, kImpactsBoxSizesYes,
- kImpactsBoxCrossReferencesNo,
+ kImpactsChildDeclaredStyleNo, kImpactsBoxGenerationYes,
+ kImpactsBoxSizesYes, kImpactsBoxCrossReferencesNo,
CreateSinglePropertyListWithValue(new StringValue("Roboto")));
// "medium" translates to 16px in Chromium.
// Cobalt does not support keyword sizes, so we simply hardcode 16px.
// https://www.w3.org/TR/css3-fonts/#font-size-prop
SetPropertyDefinition(kFontSizeProperty, "font-size", kInheritedYes,
- kAnimatableNo, kImpactsBoxGenerationYes,
- kImpactsBoxSizesYes, kImpactsBoxCrossReferencesNo,
+ kAnimatableNo, kImpactsChildDeclaredStyleYes,
+ kImpactsBoxGenerationYes, kImpactsBoxSizesYes,
+ kImpactsBoxCrossReferencesNo,
new LengthValue(16, kPixelsUnit));
// https://www.w3.org/TR/css3-fonts/#font-style-prop
SetPropertyDefinition(kFontStyleProperty, "font-style", kInheritedYes,
- kAnimatableNo, kImpactsBoxGenerationYes,
- kImpactsBoxSizesYes, kImpactsBoxCrossReferencesNo,
+ kAnimatableNo, kImpactsChildDeclaredStyleNo,
+ kImpactsBoxGenerationYes, kImpactsBoxSizesYes,
+ kImpactsBoxCrossReferencesNo,
FontStyleValue::GetNormal());
// https://www.w3.org/TR/css3-fonts/#font-weight-prop
SetPropertyDefinition(kFontWeightProperty, "font-weight", kInheritedYes,
- kAnimatableNo, kImpactsBoxGenerationYes,
- kImpactsBoxSizesYes, kImpactsBoxCrossReferencesNo,
+ kAnimatableNo, kImpactsChildDeclaredStyleNo,
+ kImpactsBoxGenerationYes, kImpactsBoxSizesYes,
+ kImpactsBoxCrossReferencesNo,
FontWeightValue::GetNormalAka400());
// https://www.w3.org/TR/CSS21/visudet.html#the-height-property
SetPropertyDefinition(kHeightProperty, "height", kInheritedNo, kAnimatableNo,
- kImpactsBoxGenerationNo, kImpactsBoxSizesYes,
- kImpactsBoxCrossReferencesNo, KeywordValue::GetAuto());
+ kImpactsChildDeclaredStyleYes, kImpactsBoxGenerationNo,
+ kImpactsBoxSizesYes, kImpactsBoxCrossReferencesNo,
+ KeywordValue::GetAuto());
// https://www.w3.org/TR/CSS2/visuren.html#propdef-left
SetPropertyDefinition(kLeftProperty, "left", kInheritedNo, kAnimatableNo,
- kImpactsBoxGenerationNo, kImpactsBoxSizesYes,
- kImpactsBoxCrossReferencesNo, KeywordValue::GetAuto());
+ kImpactsChildDeclaredStyleNo, kImpactsBoxGenerationNo,
+ kImpactsBoxSizesYes, kImpactsBoxCrossReferencesNo,
+ KeywordValue::GetAuto());
// https://www.w3.org/TR/CSS21/visudet.html#line-height
SetPropertyDefinition(kLineHeightProperty, "line-height", kInheritedYes,
- kAnimatableNo, kImpactsBoxGenerationNo,
- kImpactsBoxSizesYes, kImpactsBoxCrossReferencesNo,
+ kAnimatableNo, kImpactsChildDeclaredStyleNo,
+ kImpactsBoxGenerationNo, kImpactsBoxSizesYes,
+ kImpactsBoxCrossReferencesNo,
KeywordValue::GetNormal());
// https://www.w3.org/TR/CSS21/box.html#margin-properties
SetPropertyDefinition(kMarginBottomProperty, "margin-bottom", kInheritedNo,
- kAnimatableNo, kImpactsBoxGenerationNo,
- kImpactsBoxSizesYes, kImpactsBoxCrossReferencesNo,
+ kAnimatableNo, kImpactsChildDeclaredStyleNo,
+ kImpactsBoxGenerationNo, kImpactsBoxSizesYes,
+ kImpactsBoxCrossReferencesNo,
new LengthValue(0, kPixelsUnit));
// https://www.w3.org/TR/CSS21/box.html#margin-properties
SetPropertyDefinition(kMarginLeftProperty, "margin-left", kInheritedNo,
- kAnimatableNo, kImpactsBoxGenerationNo,
- kImpactsBoxSizesYes, kImpactsBoxCrossReferencesNo,
+ kAnimatableNo, kImpactsChildDeclaredStyleNo,
+ kImpactsBoxGenerationNo, kImpactsBoxSizesYes,
+ kImpactsBoxCrossReferencesNo,
new LengthValue(0, kPixelsUnit));
// https://www.w3.org/TR/CSS21/box.html#margin-properties
SetPropertyDefinition(kMarginRightProperty, "margin-right", kInheritedNo,
- kAnimatableNo, kImpactsBoxGenerationNo,
- kImpactsBoxSizesYes, kImpactsBoxCrossReferencesNo,
+ kAnimatableNo, kImpactsChildDeclaredStyleNo,
+ kImpactsBoxGenerationNo, kImpactsBoxSizesYes,
+ kImpactsBoxCrossReferencesNo,
new LengthValue(0, kPixelsUnit));
// https://www.w3.org/TR/CSS21/box.html#margin-properties
SetPropertyDefinition(kMarginTopProperty, "margin-top", kInheritedNo,
- kAnimatableNo, kImpactsBoxGenerationNo,
- kImpactsBoxSizesYes, kImpactsBoxCrossReferencesNo,
+ kAnimatableNo, kImpactsChildDeclaredStyleNo,
+ kImpactsBoxGenerationNo, kImpactsBoxSizesYes,
+ kImpactsBoxCrossReferencesNo,
new LengthValue(0, kPixelsUnit));
// https://www.w3.org/TR/CSS2/visudet.html#propdef-max-height
SetPropertyDefinition(kMaxHeightProperty, "max-height", kInheritedNo,
- kAnimatableNo, kImpactsBoxGenerationNo,
- kImpactsBoxSizesYes, kImpactsBoxCrossReferencesNo,
- KeywordValue::GetNone());
+ kAnimatableNo, kImpactsChildDeclaredStyleNo,
+ kImpactsBoxGenerationNo, kImpactsBoxSizesYes,
+ kImpactsBoxCrossReferencesNo, KeywordValue::GetNone());
// https://www.w3.org/TR/CSS2/visudet.html#propdef-max-width
SetPropertyDefinition(kMaxWidthProperty, "max-width", kInheritedNo,
- kAnimatableNo, kImpactsBoxGenerationNo,
- kImpactsBoxSizesYes, kImpactsBoxCrossReferencesNo,
- KeywordValue::GetNone());
+ kAnimatableNo, kImpactsChildDeclaredStyleNo,
+ kImpactsBoxGenerationNo, kImpactsBoxSizesYes,
+ kImpactsBoxCrossReferencesNo, KeywordValue::GetNone());
// https://www.w3.org/TR/CSS2/visudet.html#propdef-min-height
SetPropertyDefinition(kMinHeightProperty, "min-height", kInheritedNo,
- kAnimatableNo, kImpactsBoxGenerationNo,
- kImpactsBoxSizesYes, kImpactsBoxCrossReferencesNo,
+ kAnimatableNo, kImpactsChildDeclaredStyleNo,
+ kImpactsBoxGenerationNo, kImpactsBoxSizesYes,
+ kImpactsBoxCrossReferencesNo,
new LengthValue(0, kPixelsUnit));
// https://www.w3.org/TR/CSS2/visudet.html#propdef-min-width
SetPropertyDefinition(kMinWidthProperty, "min-width", kInheritedNo,
- kAnimatableNo, kImpactsBoxGenerationNo,
- kImpactsBoxSizesYes, kImpactsBoxCrossReferencesNo,
+ kAnimatableNo, kImpactsChildDeclaredStyleNo,
+ kImpactsBoxGenerationNo, kImpactsBoxSizesYes,
+ kImpactsBoxCrossReferencesNo,
new LengthValue(0, kPixelsUnit));
// https://www.w3.org/TR/css3-color/#opacity
SetPropertyDefinition(kOpacityProperty, "opacity", kInheritedNo,
- kAnimatableYes, kImpactsBoxGenerationNo,
- kImpactsBoxSizesNo, kImpactsBoxCrossReferencesYes,
- new NumberValue(1.0f));
+ kAnimatableYes, kImpactsChildDeclaredStyleNo,
+ kImpactsBoxGenerationNo, kImpactsBoxSizesNo,
+ kImpactsBoxCrossReferencesYes, new NumberValue(1.0f));
// https://www.w3.org/TR/css-overflow-3/#overflow-properties
SetPropertyDefinition(kOverflowProperty, "overflow", kInheritedNo,
- kAnimatableNo, kImpactsBoxGenerationNo,
- kImpactsBoxSizesNo, kImpactsBoxCrossReferencesNo,
+ kAnimatableNo, kImpactsChildDeclaredStyleNo,
+ kImpactsBoxGenerationNo, kImpactsBoxSizesYes,
+ kImpactsBoxCrossReferencesNo,
KeywordValue::GetVisible());
// https://www.w3.org/TR/css-text-3/#overflow-wrap
SetPropertyDefinition(kOverflowWrapProperty, "overflow-wrap", kInheritedYes,
- kAnimatableNo, kImpactsBoxGenerationNo,
- kImpactsBoxSizesYes, kImpactsBoxCrossReferencesNo,
+ kAnimatableNo, kImpactsChildDeclaredStyleNo,
+ kImpactsBoxGenerationNo, kImpactsBoxSizesYes,
+ kImpactsBoxCrossReferencesNo,
KeywordValue::GetNormal());
// https://www.w3.org/TR/CSS21/box.html#padding-properties
SetPropertyDefinition(kPaddingBottomProperty, "padding-bottom", kInheritedNo,
- kAnimatableNo, kImpactsBoxGenerationNo,
- kImpactsBoxSizesYes, kImpactsBoxCrossReferencesNo,
+ kAnimatableNo, kImpactsChildDeclaredStyleNo,
+ kImpactsBoxGenerationNo, kImpactsBoxSizesYes,
+ kImpactsBoxCrossReferencesNo,
new LengthValue(0, kPixelsUnit));
// https://www.w3.org/TR/CSS21/box.html#padding-properties
SetPropertyDefinition(kPaddingLeftProperty, "padding-left", kInheritedNo,
- kAnimatableNo, kImpactsBoxGenerationNo,
- kImpactsBoxSizesYes, kImpactsBoxCrossReferencesNo,
+ kAnimatableNo, kImpactsChildDeclaredStyleNo,
+ kImpactsBoxGenerationNo, kImpactsBoxSizesYes,
+ kImpactsBoxCrossReferencesNo,
new LengthValue(0, kPixelsUnit));
// https://www.w3.org/TR/CSS21/box.html#padding-properties
SetPropertyDefinition(kPaddingRightProperty, "padding-right", kInheritedNo,
- kAnimatableNo, kImpactsBoxGenerationNo,
- kImpactsBoxSizesYes, kImpactsBoxCrossReferencesNo,
+ kAnimatableNo, kImpactsChildDeclaredStyleNo,
+ kImpactsBoxGenerationNo, kImpactsBoxSizesYes,
+ kImpactsBoxCrossReferencesNo,
new LengthValue(0, kPixelsUnit));
// https://www.w3.org/TR/CSS21/box.html#padding-properties
SetPropertyDefinition(kPaddingTopProperty, "padding-top", kInheritedNo,
- kAnimatableNo, kImpactsBoxGenerationNo,
- kImpactsBoxSizesYes, kImpactsBoxCrossReferencesNo,
+ kAnimatableNo, kImpactsChildDeclaredStyleNo,
+ kImpactsBoxGenerationNo, kImpactsBoxSizesYes,
+ kImpactsBoxCrossReferencesNo,
new LengthValue(0, kPixelsUnit));
// https://www.w3.org/TR/css3-positioning/#position-property
SetPropertyDefinition(kPositionProperty, "position", kInheritedNo,
- kAnimatableNo, kImpactsBoxGenerationYes,
- kImpactsBoxSizesYes, kImpactsBoxCrossReferencesYes,
+ kAnimatableNo, kImpactsChildDeclaredStyleNo,
+ kImpactsBoxGenerationYes, kImpactsBoxSizesYes,
+ kImpactsBoxCrossReferencesYes,
KeywordValue::GetStatic());
// https://www.w3.org/TR/CSS2/visuren.html#propdef-right
SetPropertyDefinition(kRightProperty, "right", kInheritedNo, kAnimatableNo,
- kImpactsBoxGenerationNo, kImpactsBoxSizesYes,
- kImpactsBoxCrossReferencesNo, KeywordValue::GetAuto());
+ kImpactsChildDeclaredStyleNo, kImpactsBoxGenerationNo,
+ kImpactsBoxSizesYes, kImpactsBoxCrossReferencesNo,
+ KeywordValue::GetAuto());
// https://www.w3.org/TR/css-text-3/#text-align
SetPropertyDefinition(kTextAlignProperty, "text-align", kInheritedYes,
- kAnimatableNo, kImpactsBoxGenerationNo,
- kImpactsBoxSizesYes, kImpactsBoxCrossReferencesNo,
- KeywordValue::GetStart());
+ kAnimatableNo, kImpactsChildDeclaredStyleNo,
+ kImpactsBoxGenerationNo, kImpactsBoxSizesYes,
+ kImpactsBoxCrossReferencesNo, KeywordValue::GetStart());
// https://www.w3.org/TR/css-text-decor-3/#text-decoration-color
SetPropertyDefinition(kTextDecorationColorProperty, "text-decoration-color",
- kInheritedNo, kAnimatableYes, kImpactsBoxGenerationNo,
+ kInheritedNo, kAnimatableYes,
+ kImpactsChildDeclaredStyleNo, kImpactsBoxGenerationNo,
kImpactsBoxSizesNo, kImpactsBoxCrossReferencesNo,
KeywordValue::GetCurrentColor());
// https://www.w3.org/TR/css-text-decor-3/#text-decoration-line
SetPropertyDefinition(kTextDecorationLineProperty, "text-decoration-line",
- kInheritedNo, kAnimatableNo, kImpactsBoxGenerationNo,
+ kInheritedNo, kAnimatableNo,
+ kImpactsChildDeclaredStyleNo, kImpactsBoxGenerationNo,
kImpactsBoxSizesNo, kImpactsBoxCrossReferencesNo,
KeywordValue::GetNone());
// https://www.w3.org/TR/CSS21/text.html#propdef-text-indent
SetPropertyDefinition(kTextIndentProperty, "text-indent", kInheritedYes,
- kAnimatableNo, kImpactsBoxGenerationNo,
- kImpactsBoxSizesYes, kImpactsBoxCrossReferencesNo,
+ kAnimatableNo, kImpactsChildDeclaredStyleNo,
+ kImpactsBoxGenerationNo, kImpactsBoxSizesYes,
+ kImpactsBoxCrossReferencesNo,
new LengthValue(0, kPixelsUnit));
// https://www.w3.org/TR/css3-ui/#propdef-text-overflow
SetPropertyDefinition(kTextOverflowProperty, "text-overflow", kInheritedNo,
- kAnimatableNo, kImpactsBoxGenerationNo,
- kImpactsBoxSizesNo, kImpactsBoxCrossReferencesNo,
- KeywordValue::GetClip());
+ kAnimatableNo, kImpactsChildDeclaredStyleNo,
+ kImpactsBoxGenerationNo, kImpactsBoxSizesYes,
+ kImpactsBoxCrossReferencesNo, KeywordValue::GetClip());
// https://www.w3.org/TR/css-text-decor-3/#text-shadow-property
SetPropertyDefinition(kTextShadowProperty, "text-shadow", kInheritedYes,
- kAnimatableNo, kImpactsBoxGenerationNo,
- kImpactsBoxSizesNo, kImpactsBoxCrossReferencesNo,
- KeywordValue::GetNone());
+ kAnimatableNo, kImpactsChildDeclaredStyleNo,
+ kImpactsBoxGenerationNo, kImpactsBoxSizesNo,
+ kImpactsBoxCrossReferencesNo, KeywordValue::GetNone());
// https://www.w3.org/TR/css3-text/#text-transform-property
SetPropertyDefinition(kTextTransformProperty, "text-transform", kInheritedYes,
- kAnimatableNo, kImpactsBoxGenerationYes,
- kImpactsBoxSizesNo, kImpactsBoxCrossReferencesNo,
- KeywordValue::GetNone());
+ kAnimatableNo, kImpactsChildDeclaredStyleNo,
+ kImpactsBoxGenerationYes, kImpactsBoxSizesNo,
+ kImpactsBoxCrossReferencesNo, KeywordValue::GetNone());
// https://www.w3.org/TR/CSS2/visuren.html#propdef-top
SetPropertyDefinition(kTopProperty, "top", kInheritedNo, kAnimatableNo,
- kImpactsBoxGenerationNo, kImpactsBoxSizesYes,
- kImpactsBoxCrossReferencesNo, KeywordValue::GetAuto());
+ kImpactsChildDeclaredStyleNo, kImpactsBoxGenerationNo,
+ kImpactsBoxSizesYes, kImpactsBoxCrossReferencesNo,
+ KeywordValue::GetAuto());
// https://www.w3.org/TR/css3-transforms/#transform-property
SetPropertyDefinition(kTransformProperty, "transform", kInheritedNo,
- kAnimatableYes, kImpactsBoxGenerationNo,
- kImpactsBoxSizesYes, kImpactsBoxCrossReferencesYes,
- KeywordValue::GetNone());
+ kAnimatableYes, kImpactsChildDeclaredStyleNo,
+ kImpactsBoxGenerationNo, kImpactsBoxSizesYes,
+ kImpactsBoxCrossReferencesYes, KeywordValue::GetNone());
// https://www.w3.org/TR/css3-transforms/#propdef-transform-origin
scoped_ptr<PropertyListValue::Builder> transform_origin_builder(
@@ -568,88 +617,94 @@
transform_origin_builder->push_back(new LengthValue(0.0f, kPixelsUnit));
scoped_refptr<PropertyListValue> transform_origin_list(
new PropertyListValue(transform_origin_builder.Pass()));
- SetPropertyDefinition(kTransformOriginProperty, "transform-origin",
- kInheritedNo, kAnimatableNo, kImpactsBoxGenerationNo,
- kImpactsBoxSizesNo, kImpactsBoxCrossReferencesNo,
- transform_origin_list);
+ SetPropertyDefinition(
+ kTransformOriginProperty, "transform-origin", kInheritedNo, kAnimatableNo,
+ kImpactsChildDeclaredStyleNo, kImpactsBoxGenerationNo, kImpactsBoxSizesNo,
+ kImpactsBoxCrossReferencesNo, transform_origin_list);
// https://www.w3.org/TR/css3-transitions/#transition-delay-property
- SetPropertyDefinition(kTransitionDelayProperty, "transition-delay",
- kInheritedNo, kAnimatableNo, kImpactsBoxGenerationNo,
- kImpactsBoxSizesNo, kImpactsBoxCrossReferencesNo,
- CreateTimeListWithZeroSeconds());
+ SetPropertyDefinition(
+ kTransitionDelayProperty, "transition-delay", kInheritedNo, kAnimatableNo,
+ kImpactsChildDeclaredStyleNo, kImpactsBoxGenerationNo, kImpactsBoxSizesNo,
+ kImpactsBoxCrossReferencesNo, CreateTimeListWithZeroSeconds());
// https://www.w3.org/TR/css3-transitions/#transition-duration-property
SetPropertyDefinition(kTransitionDurationProperty, "transition-duration",
- kInheritedNo, kAnimatableNo, kImpactsBoxGenerationNo,
+ kInheritedNo, kAnimatableNo,
+ kImpactsChildDeclaredStyleNo, kImpactsBoxGenerationNo,
kImpactsBoxSizesNo, kImpactsBoxCrossReferencesNo,
CreateTimeListWithZeroSeconds());
// https://www.w3.org/TR/css3-transitions/#transition-property-property
SetPropertyDefinition(kTransitionPropertyProperty, "transition-property",
- kInheritedNo, kAnimatableNo, kImpactsBoxGenerationNo,
+ kInheritedNo, kAnimatableNo,
+ kImpactsChildDeclaredStyleNo, kImpactsBoxGenerationNo,
kImpactsBoxSizesNo, kImpactsBoxCrossReferencesNo,
CreatePropertyKeyListWithAll());
// https://www.w3.org/TR/css3-transitions/#transition-timing-function-property
- SetPropertyDefinition(kTransitionTimingFunctionProperty,
- "transition-timing-function", kInheritedNo,
- kAnimatableNo, kImpactsBoxGenerationNo,
- kImpactsBoxSizesNo, kImpactsBoxCrossReferencesNo,
- CreateTransitionTimingFunctionListWithEase());
+ SetPropertyDefinition(
+ kTransitionTimingFunctionProperty, "transition-timing-function",
+ kInheritedNo, kAnimatableNo, kImpactsChildDeclaredStyleNo,
+ kImpactsBoxGenerationNo, kImpactsBoxSizesNo, kImpactsBoxCrossReferencesNo,
+ CreateTransitionTimingFunctionListWithEase());
// https://www.w3.org/TR/CSS21/visudet.html#propdef-vertical-align
- SetPropertyDefinition(kVerticalAlignProperty, "vertical-align", kInheritedNo,
- kAnimatableNo, kImpactsBoxGenerationNo,
- kImpactsBoxSizesNo, kImpactsBoxCrossReferencesNo,
- KeywordValue::GetBaseline());
+ SetPropertyDefinition(
+ kVerticalAlignProperty, "vertical-align", kInheritedNo, kAnimatableNo,
+ kImpactsChildDeclaredStyleNo, kImpactsBoxGenerationNo, kImpactsBoxSizesNo,
+ kImpactsBoxCrossReferencesNo, KeywordValue::GetBaseline());
// https://www.w3.org/TR/CSS21/visufx.html#propdef-visibility
- SetPropertyDefinition(kVisibilityProperty, "visibility", kInheritedYes,
- kAnimatableNo, kImpactsBoxGenerationNo,
- kImpactsBoxSizesNo, kImpactsBoxCrossReferencesNo,
- KeywordValue::GetVisible());
+ SetPropertyDefinition(
+ kVisibilityProperty, "visibility", kInheritedYes, kAnimatableNo,
+ kImpactsChildDeclaredStyleNo, kImpactsBoxGenerationNo, kImpactsBoxSizesNo,
+ kImpactsBoxCrossReferencesNo, KeywordValue::GetVisible());
// https://www.w3.org/TR/css3-text/#white-space-property
SetPropertyDefinition(kWhiteSpaceProperty, "white-space", kInheritedYes,
- kAnimatableNo, kImpactsBoxGenerationYes,
- kImpactsBoxSizesYes, kImpactsBoxCrossReferencesNo,
+ kAnimatableNo, kImpactsChildDeclaredStyleNo,
+ kImpactsBoxGenerationYes, kImpactsBoxSizesYes,
+ kImpactsBoxCrossReferencesNo,
KeywordValue::GetNormal());
// https://www.w3.org/TR/CSS21/visudet.html#the-width-property
SetPropertyDefinition(kWidthProperty, "width", kInheritedNo, kAnimatableNo,
- kImpactsBoxGenerationNo, kImpactsBoxSizesYes,
- kImpactsBoxCrossReferencesNo, KeywordValue::GetAuto());
+ kImpactsChildDeclaredStyleYes, kImpactsBoxGenerationNo,
+ kImpactsBoxSizesYes, kImpactsBoxCrossReferencesNo,
+ KeywordValue::GetAuto());
// https://www.w3.org/TR/CSS21/visuren.html#z-index
SetPropertyDefinition(kZIndexProperty, "z-index", kInheritedNo, kAnimatableNo,
- kImpactsBoxGenerationNo, kImpactsBoxSizesNo,
- kImpactsBoxCrossReferencesYes, KeywordValue::GetAuto());
+ kImpactsChildDeclaredStyleNo, kImpactsBoxGenerationNo,
+ kImpactsBoxSizesNo, kImpactsBoxCrossReferencesYes,
+ KeywordValue::GetAuto());
// This property name can appear as a keyword for the transition-property
// property.
// https://www.w3.org/TR/2013/WD-css3-transitions-20131119/#transition-property-property
SetPropertyDefinition(kAllProperty, "all", kInheritedNo, kAnimatableNo,
- kImpactsBoxGenerationNo, kImpactsBoxSizesNo,
- kImpactsBoxCrossReferencesNo, NULL);
+ kImpactsChildDeclaredStyleNo, kImpactsBoxGenerationNo,
+ kImpactsBoxSizesNo, kImpactsBoxCrossReferencesNo, NULL);
// This is a descriptor for @font-face at-rules.
// https://www.w3.org/TR/css3-fonts/#descdef-src
SetPropertyDefinition(kSrcProperty, "src", kInheritedNo, kAnimatableNo,
- kImpactsBoxGenerationNo, kImpactsBoxSizesNo,
- kImpactsBoxCrossReferencesNo, NULL);
+ kImpactsChildDeclaredStyleNo, kImpactsBoxGenerationNo,
+ kImpactsBoxSizesNo, kImpactsBoxCrossReferencesNo, NULL);
// https://www.w3.org/TR/css3-fonts/#unicode-range-desc
- SetPropertyDefinition(kUnicodeRangeProperty, "unicode-range", kInheritedNo,
- kAnimatableNo, kImpactsBoxGenerationNo,
- kImpactsBoxSizesNo, kImpactsBoxCrossReferencesNo,
- new UnicodeRangeValue(0, 0x10FFFF));
+ SetPropertyDefinition(
+ kUnicodeRangeProperty, "unicode-range", kInheritedNo, kAnimatableNo,
+ kImpactsChildDeclaredStyleNo, kImpactsBoxGenerationNo, kImpactsBoxSizesNo,
+ kImpactsBoxCrossReferencesNo, new UnicodeRangeValue(0, 0x10FFFF));
// This is an alias for kOverflowWrap
// https://www.w3.org/TR/css-text-3/#overflow-wrap
SetPropertyDefinition(kWordWrapProperty, "word-wrap", kInheritedYes,
- kAnimatableNo, kImpactsBoxGenerationNo,
- kImpactsBoxSizesYes, kImpactsBoxCrossReferencesNo,
+ kAnimatableNo, kImpactsChildDeclaredStyleNo,
+ kImpactsBoxGenerationNo, kImpactsBoxSizesYes,
+ kImpactsBoxCrossReferencesNo,
KeywordValue::GetNormal());
// Shorthand properties.
@@ -790,6 +845,9 @@
for (int i = 0; i < kMaxEveryPropertyKey + 1; ++i) {
if (properties[i].animatable == kAnimatableYes) {
animatable_properties.push_back(static_cast<PropertyKey>(i));
+ if (properties[i].inherited == kInheritedYes) {
+ inherited_animatable_properties.push_back(static_cast<PropertyKey>(i));
+ }
}
}
}
@@ -842,6 +900,16 @@
return non_trivial_global_variables.Get().properties[key].animatable;
}
+ImpactsChildDeclaredStyle GetPropertyImpactsChildDeclaredStyle(
+ PropertyKey key) {
+ DCHECK(!IsShorthandProperty(key));
+ DCHECK_GT(key, kNoneProperty);
+ DCHECK_LE(key, kMaxEveryPropertyKey);
+ return non_trivial_global_variables.Get()
+ .properties[key]
+ .impacts_child_declared_style;
+}
+
ImpactsBoxGeneration GetPropertyImpactsBoxGeneration(PropertyKey key) {
DCHECK(!IsShorthandProperty(key));
DCHECK_GT(key, kNoneProperty);
@@ -877,10 +945,14 @@
return non_trivial_global_variables.Get().properties[key].longhand_properties;
}
-const AnimatablePropertyList& GetAnimatableProperties() {
+const PropertyKeyVector& GetAnimatableProperties() {
return non_trivial_global_variables.Get().animatable_properties;
}
+const PropertyKeyVector& GetInheritedAnimatableProperties() {
+ return non_trivial_global_variables.Get().inherited_animatable_properties;
+}
+
PropertyKey GetLexicographicalLonghandPropertyKey(const size_t index) {
DCHECK_LE(
index,
diff --git a/src/cobalt/cssom/property_definitions.h b/src/cobalt/cssom/property_definitions.h
index bbaf9a3..14a1c39 100644
--- a/src/cobalt/cssom/property_definitions.h
+++ b/src/cobalt/cssom/property_definitions.h
@@ -157,16 +157,33 @@
kAnimatableYes,
};
+// Any property that is referenced when calculating the declared property values
+// of children should have this set to true.
+// NOTE: This currently occurs within CalculateComputedStyleContext.
+enum ImpactsChildDeclaredStyle {
+ kImpactsChildDeclaredStyleNo,
+ kImpactsChildDeclaredStyleYes,
+};
+
+// Any property that is referenced during box generation should have this set to
+// true.
+// NOTE: This currently occurs within BoxGenerator.
enum ImpactsBoxGeneration {
kImpactsBoxGenerationNo,
kImpactsBoxGenerationYes,
};
+// Any property that is referenced when updating the size of boxes should have
+// this set to true.
+// NOTE: This currently occurs within Box::UpdateSize().
enum ImpactsBoxSizes {
kImpactsBoxSizesNo,
kImpactsBoxSizesYes,
};
+// Any property that is referenced when generating cross references should have
+// this set to true.
+// NOTE: This currently occurs within ContainerBox::UpdateCrossReferences().
enum ImpactsBoxCrossReferences {
kImpactsBoxCrossReferencesNo,
kImpactsBoxCrossReferencesYes,
@@ -183,12 +200,14 @@
Inherited GetPropertyInheritance(PropertyKey key);
Animatable GetPropertyAnimatable(PropertyKey key);
+ImpactsChildDeclaredStyle GetPropertyImpactsChildDeclaredStyle(PropertyKey key);
ImpactsBoxGeneration GetPropertyImpactsBoxGeneration(PropertyKey key);
ImpactsBoxSizes GetPropertyImpactsBoxSizes(PropertyKey key);
ImpactsBoxCrossReferences GetPropertyImpactsBoxCrossReferences(PropertyKey key);
-typedef std::vector<PropertyKey> AnimatablePropertyList;
-const AnimatablePropertyList& GetAnimatableProperties();
+typedef std::vector<PropertyKey> PropertyKeyVector;
+const PropertyKeyVector& GetAnimatableProperties();
+const PropertyKeyVector& GetInheritedAnimatableProperties();
PropertyKey GetLexicographicalLonghandPropertyKey(const size_t index);
@@ -203,7 +222,6 @@
const LonghandPropertySet& ExpandShorthandProperty(PropertyKey key);
typedef std::bitset<kNumLonghandProperties> LonghandPropertiesBitset;
-typedef std::vector<PropertyKey> PropertyKeyVector;
} // namespace cssom
} // namespace cobalt
diff --git a/src/cobalt/debug/render_overlay.cc b/src/cobalt/debug/render_overlay.cc
index 85d03b0..5a60043 100644
--- a/src/cobalt/debug/render_overlay.cc
+++ b/src/cobalt/debug/render_overlay.cc
@@ -25,7 +25,7 @@
RenderOverlay::RenderOverlay(
const OnRenderTreeProducedCallback& render_tree_produced_callback)
: render_tree_produced_callback_(render_tree_produced_callback),
- input_layout_(NULL, NULL, base::TimeDelta()) {}
+ input_layout_(NULL, base::TimeDelta()) {}
void RenderOverlay::OnRenderTreeProduced(const LayoutResults& layout_results) {
input_layout_ = layout_results;
@@ -56,10 +56,10 @@
new render_tree::CompositionNode(builder);
render_tree_produced_callback_.Run(
- LayoutResults(combined_tree, input_layout_.animations, layout_time));
+ LayoutResults(combined_tree, layout_time));
} else {
- render_tree_produced_callback_.Run(LayoutResults(
- input_layout_.render_tree, input_layout_.animations, layout_time));
+ render_tree_produced_callback_.Run(
+ LayoutResults(input_layout_.render_tree, layout_time));
}
}
}
diff --git a/src/cobalt/dom/Document.idl b/src/cobalt/dom/Document.idl
index 73fa7e6..d33334d 100644
--- a/src/cobalt/dom/Document.idl
+++ b/src/cobalt/dom/Document.idl
@@ -22,6 +22,10 @@
readonly attribute DOMString documentURI;
readonly attribute Element? documentElement;
+ // Non-standard return type, should be WindowProxy.
+ // https://www.w3.org/TR/html5/single-page.html#dom-document-defaultview
+ readonly attribute Window? defaultView;
+
HTMLCollection getElementsByTagName(DOMString localName);
HTMLCollection getElementsByClassName(DOMString classNames);
[NewObject] Element createElement(DOMString localName);
diff --git a/src/cobalt/dom/HTMLVideoElement.idl b/src/cobalt/dom/HTMLVideoElement.idl
index 3793eab..7f44060 100644
--- a/src/cobalt/dom/HTMLVideoElement.idl
+++ b/src/cobalt/dom/HTMLVideoElement.idl
@@ -21,4 +21,7 @@
attribute unsigned long height;
readonly attribute unsigned long videoWidth;
readonly attribute unsigned long videoHeight;
+
+ // https://www.w3.org/TR/media-source/#widl-HTMLVideoElement-getVideoPlaybackQuality-VideoPlaybackQuality
+ VideoPlaybackQuality getVideoPlaybackQuality();
};
diff --git a/src/cobalt/dom/VideoPlaybackQuality.idl b/src/cobalt/dom/VideoPlaybackQuality.idl
new file mode 100644
index 0000000..8263a07
--- /dev/null
+++ b/src/cobalt/dom/VideoPlaybackQuality.idl
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2016 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.
+ */
+
+// https://www.w3.org/TR/media-source/#idl-def-VideoPlaybackQuality
+
+interface VideoPlaybackQuality {
+ readonly attribute DOMHighResTimeStamp creationTime;
+ readonly attribute unsigned long totalVideoFrames;
+ readonly attribute unsigned long droppedVideoFrames;
+ readonly attribute unsigned long corruptedVideoFrames;
+ readonly attribute double totalFrameDelay;
+};
+
+typedef double DOMHighResTimeStamp;
diff --git a/src/cobalt/dom/document.cc b/src/cobalt/dom/document.cc
index cc586b7..0d2b543 100644
--- a/src/cobalt/dom/document.cc
+++ b/src/cobalt/dom/document.cc
@@ -53,6 +53,7 @@
#include "cobalt/dom/node_descendants_iterator.h"
#include "cobalt/dom/text.h"
#include "cobalt/dom/ui_event.h"
+#include "cobalt/dom/window.h"
namespace cobalt {
namespace dom {
@@ -61,6 +62,7 @@
const Options& options)
: ALLOW_THIS_IN_INITIALIZER_LIST(Node(this)),
html_element_context_(html_element_context),
+ window_(options.window),
implementation_(new DOMImplementation()),
ALLOW_THIS_IN_INITIALIZER_LIST(
style_sheets_(new cssom::StyleSheetList(this))),
@@ -81,7 +83,9 @@
navigation_start_clock_(options.navigation_start_clock),
ALLOW_THIS_IN_INITIALIZER_LIST(
default_timeline_(new DocumentTimeline(this, 0))),
- user_agent_style_sheet_(options.user_agent_style_sheet) {
+ user_agent_style_sheet_(options.user_agent_style_sheet),
+ initial_computed_style_declaration_(
+ new cssom::CSSComputedStyleDeclaration()) {
DCHECK(options.url.is_empty() || options.url.is_valid());
if (options.viewport_size) {
@@ -141,6 +145,8 @@
return first_element_child();
}
+scoped_refptr<Window> Document::default_view() const { return window_; }
+
std::string Document::title() const {
const char kTitleTag[] = "title";
if (head()) {
@@ -543,14 +549,14 @@
scoped_refptr<HTMLElement> root = html();
if (root) {
// First update the computed style for root element.
- root->UpdateComputedStyle(initial_computed_style_,
- initial_computed_style_,
+ root->UpdateComputedStyle(initial_computed_style_declaration_,
+ initial_computed_style_data_,
style_change_event_time);
// Then update the computed styles for the other elements.
- root->UpdateComputedStyleRecursively(root->computed_style(),
- root->computed_style(),
- style_change_event_time, true);
+ root->UpdateComputedStyleRecursively(
+ root->css_computed_style_declaration(), root->computed_style(),
+ style_change_event_time, true);
}
is_computed_style_dirty_ = false;
@@ -589,9 +595,16 @@
void Document::SetViewport(const math::Size& viewport_size) {
viewport_size_ = viewport_size;
- initial_computed_style_ = CreateInitialComputedStyle(*viewport_size_);
+ initial_computed_style_data_ = CreateInitialComputedStyle(*viewport_size_);
+ initial_computed_style_declaration_->SetData(initial_computed_style_data_);
+
is_computed_style_dirty_ = true;
is_selector_tree_dirty_ = true;
+
+ scoped_refptr<HTMLHtmlElement> current_html = html();
+ if (current_html) {
+ current_html->InvalidateComputedStylesRecursively();
+ }
}
Document::~Document() {
@@ -682,6 +695,13 @@
keyframes_map_updater.ProcessCSSStyleSheet(user_agent_style_sheet_);
keyframes_map_updater.ProcessStyleSheetList(style_sheets());
are_keyframes_dirty_ = false;
+
+ // This should eventually be altered to only invalidate the tree when the
+ // the keyframes map changed.
+ scoped_refptr<HTMLHtmlElement> current_html = html();
+ if (current_html) {
+ current_html->InvalidateComputedStylesRecursively();
+ }
}
}
diff --git a/src/cobalt/dom/document.h b/src/cobalt/dom/document.h
index a312b1a..4d45315 100644
--- a/src/cobalt/dom/document.h
+++ b/src/cobalt/dom/document.h
@@ -27,7 +27,7 @@
#include "base/optional.h"
#include "base/string_piece.h"
#include "cobalt/base/clock.h"
-#include "cobalt/cssom/css_computed_style_data.h"
+#include "cobalt/cssom/css_computed_style_declaration.h"
#include "cobalt/cssom/css_keyframes_rule.h"
#include "cobalt/cssom/css_style_sheet.h"
#include "cobalt/cssom/mutation_observer.h"
@@ -61,6 +61,7 @@
class HTMLScriptElement;
class Location;
class Text;
+class Window;
class DocumentObserver {
public:
@@ -88,9 +89,11 @@
Options() : cookie_jar(NULL), csp_enforcement_mode(kCspEnforcementEnable) {}
explicit Options(const GURL& url_value)
: url(url_value),
+ window(NULL),
cookie_jar(NULL),
csp_enforcement_mode(kCspEnforcementEnable) {}
- Options(const GURL& url_value, const base::Closure& hashchange_callback,
+ Options(const GURL& url_value, Window* window,
+ const base::Closure& hashchange_callback,
const scoped_refptr<base::Clock>& navigation_start_clock_value,
const base::Callback<void(const GURL&)>& navigation_callback,
const scoped_refptr<cssom::CSSStyleSheet> user_agent_style_sheet,
@@ -102,6 +105,7 @@
const base::Closure& csp_policy_changed_callback,
int csp_insecure_allowed_token = 0)
: url(url_value),
+ window(window),
hashchange_callback(hashchange_callback),
navigation_start_clock(navigation_start_clock_value),
navigation_callback(navigation_callback),
@@ -115,6 +119,7 @@
csp_insecure_allowed_token(csp_insecure_allowed_token) {}
GURL url;
+ Window* window;
base::Closure hashchange_callback;
scoped_refptr<base::Clock> navigation_start_clock;
base::Callback<void(const GURL&)> navigation_callback;
@@ -145,6 +150,8 @@
scoped_refptr<Element> document_element() const;
std::string title() const;
+ scoped_refptr<Window> default_view() const;
+
scoped_refptr<HTMLCollection> GetElementsByTagName(
const std::string& local_name) const;
scoped_refptr<HTMLCollection> GetElementsByClassName(
@@ -298,9 +305,13 @@
math::Size viewport_size() { return viewport_size_.value_or(math::Size()); }
void SetViewport(const math::Size& viewport_size);
- const scoped_refptr<cssom::CSSComputedStyleData>& initial_computed_style()
- const {
- return initial_computed_style_;
+ const scoped_refptr<cssom::CSSComputedStyleDeclaration>&
+ initial_computed_style_declaration() const {
+ return initial_computed_style_declaration_;
+ }
+ const scoped_refptr<cssom::CSSComputedStyleData>&
+ initial_computed_style_data() const {
+ return initial_computed_style_data_;
}
void NotifyUrlChanged(const GURL& url);
@@ -334,6 +345,9 @@
// Reference to HTML element context.
HTMLElementContext* const html_element_context_;
+ // Reference to the Window object. We cannot hold a strong reference,
+ // otherwise we create a reference loop.
+ Window* window_;
// Associated DOM implementation object.
scoped_refptr<DOMImplementation> implementation_;
// Associated location object.
@@ -387,7 +401,9 @@
// Computed style of the initial containing block, width and height come from
// the viewport size.
- scoped_refptr<cssom::CSSComputedStyleData> initial_computed_style_;
+ scoped_refptr<cssom::CSSComputedStyleDeclaration>
+ initial_computed_style_declaration_;
+ scoped_refptr<cssom::CSSComputedStyleData> initial_computed_style_data_;
};
} // namespace dom
diff --git a/src/cobalt/dom/dom.gyp b/src/cobalt/dom/dom.gyp
index d171fd3..5438684 100644
--- a/src/cobalt/dom/dom.gyp
+++ b/src/cobalt/dom/dom.gyp
@@ -64,8 +64,6 @@
'document_type.h',
'dom_animatable.cc',
'dom_animatable.h',
- 'dom_exception.cc',
- 'dom_exception.h',
'dom_implementation.cc',
'dom_implementation.h',
'dom_parser.cc',
@@ -248,6 +246,7 @@
'<(DEPTH)/cobalt/base/base.gyp:base',
'<(DEPTH)/cobalt/csp/csp.gyp:csp',
'<(DEPTH)/cobalt/cssom/cssom.gyp:cssom',
+ '<(DEPTH)/cobalt/dom/dom_exception.gyp:dom_exception',
'<(DEPTH)/cobalt/loader/loader.gyp:loader',
'<(DEPTH)/cobalt/media/media.gyp:media',
# Interface layer to avoid directly depending on network.
diff --git a/src/cobalt/dom/dom_exception.gyp b/src/cobalt/dom/dom_exception.gyp
new file mode 100644
index 0000000..ba6dcf6
--- /dev/null
+++ b/src/cobalt/dom/dom_exception.gyp
@@ -0,0 +1,32 @@
+# Copyright 2016 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': {
+ 'cobalt_code': 1,
+ },
+ 'targets': [
+ {
+ 'target_name': 'dom_exception',
+ 'type': 'static_library',
+ 'sources': [
+ 'dom_exception.cc',
+ 'dom_exception.h',
+ ],
+ 'dependencies': [
+ '<(DEPTH)/cobalt/script/script.gyp:script',
+ ],
+ },
+ ],
+}
diff --git a/src/cobalt/dom/html_element.cc b/src/cobalt/dom/html_element.cc
index 29cbf3e..f63dbbf 100644
--- a/src/cobalt/dom/html_element.cc
+++ b/src/cobalt/dom/html_element.cc
@@ -77,18 +77,22 @@
struct NonTrivialStaticFields {
NonTrivialStaticFields() {
+ cssom::PropertyKeyVector computed_style_invalidation_properties;
cssom::PropertyKeyVector layout_box_invalidation_properties;
cssom::PropertyKeyVector size_invalidation_properties;
cssom::PropertyKeyVector cross_references_invalidation_properties;
for (int i = 0; i <= cssom::kMaxLonghandPropertyKey; ++i) {
cssom::PropertyKey property_key = static_cast<cssom::PropertyKey>(i);
- // TODO: Only invalidate layout boxes when a property that is used
- // for box generation is modified. We currently have to also invalidate
- // when any inheritable property is modified, because AnonymousBlockBox
- // and TextBox use GetComputedStyleOfAnonymousBox() to store a copy of
- // them that won't automatically get updated when the style() in a
- // CSSComputedStyleDeclaration gets updated.
+
+ if (cssom::GetPropertyImpactsChildDeclaredStyle(property_key) ==
+ cssom::kImpactsChildDeclaredStyleYes) {
+ computed_style_invalidation_properties.push_back(property_key);
+ }
+
+ // TODO: Revisit inherited property handling. Currently, all boxes are
+ // invalidated if an inherited property changes, but now that inherited
+ // properties dynamically update, this is likely no longer necessary.
if (cssom::GetPropertyInheritance(property_key) == cssom::kInheritedYes ||
cssom::GetPropertyImpactsBoxGeneration(property_key) ==
cssom::kImpactsBoxGenerationYes) {
@@ -105,6 +109,9 @@
}
}
+ computed_style_invalidation_property_checker =
+ cssom::CSSComputedStyleData::PropertySetMatcher(
+ computed_style_invalidation_properties);
layout_box_invalidation_property_checker =
cssom::CSSComputedStyleData::PropertySetMatcher(
layout_box_invalidation_properties);
@@ -117,6 +124,8 @@
}
cssom::CSSComputedStyleData::PropertySetMatcher
+ computed_style_invalidation_property_checker;
+ cssom::CSSComputedStyleData::PropertySetMatcher
layout_box_invalidation_property_checker;
cssom::CSSComputedStyleData::PropertySetMatcher
size_invalidation_property_checker;
@@ -570,9 +579,13 @@
}
matching_rules_valid_ = false;
- computed_style_valid_ = false;
- matching_rules_.clear();
+ // Move |matching_rules_| into |old_matching_rules_|. This is used for
+ // determining whether or not the matching rules actually changed when they
+ // are updated.
+ old_matching_rules_.swap(matching_rules_);
+
+ matching_rules_->clear();
rule_matching_state_.matching_nodes.clear();
rule_matching_state_.descendant_potential_nodes.clear();
rule_matching_state_.following_sibling_potential_nodes.clear();
@@ -603,17 +616,28 @@
}
}
+void HTMLElement::InvalidateComputedStylesRecursively() {
+ computed_style_valid_ = false;
+
+ for (Element* element = first_element_child(); element;
+ element = element->next_element_sibling()) {
+ HTMLElement* html_element = element->AsHTMLElement();
+ DCHECK(html_element);
+ html_element->InvalidateComputedStylesRecursively();
+ }
+}
+
void HTMLElement::UpdateComputedStyleRecursively(
- const scoped_refptr<const cssom::CSSComputedStyleData>&
- parent_computed_style,
+ const scoped_refptr<cssom::CSSComputedStyleDeclaration>&
+ parent_computed_style_declaration,
const scoped_refptr<const cssom::CSSComputedStyleData>& root_computed_style,
const base::TimeDelta& style_change_event_time, bool ancestors_were_valid) {
// Update computed style for this element.
- bool is_valid = ancestors_were_valid && computed_style_valid_;
+ bool is_valid =
+ ancestors_were_valid && matching_rules_valid_ && computed_style_valid_;
if (!is_valid) {
- UpdateComputedStyle(parent_computed_style, root_computed_style,
+ UpdateComputedStyle(parent_computed_style_declaration, root_computed_style,
style_change_event_time);
- computed_style_valid_ = true;
}
// Do not update computed style for descendants of "display: none" elements,
@@ -630,8 +654,8 @@
HTMLElement* html_element = element->AsHTMLElement();
DCHECK(html_element);
html_element->UpdateComputedStyleRecursively(
- computed_style(), root_computed_style, style_change_event_time,
- is_valid);
+ css_computed_style_declaration(), root_computed_style,
+ style_change_event_time, is_valid);
}
}
@@ -657,6 +681,12 @@
}
}
+void HTMLElement::InvalidateRenderTreeNodesFromNode() {
+ if (layout_boxes_) {
+ layout_boxes_->InvalidateRenderTreeNodes();
+ }
+}
+
HTMLElement::HTMLElement(Document* document, base::Token tag_name)
: Element(document, tag_name),
directionality_(kNoExplicitDirectionality),
@@ -670,6 +700,8 @@
ALLOW_THIS_IN_INITIALIZER_LIST(
animations_adapter_(new DOMAnimatable(this))),
css_animations_(&animations_adapter_),
+ old_matching_rules_(new cssom::RulesWithCascadePrecedence()),
+ matching_rules_(new cssom::RulesWithCascadePrecedence()),
matching_rules_valid_(false),
dom_stat_tracker_(document->html_element_context()->dom_stat_tracker()) {
css_computed_style_declaration_->set_animations(animations());
@@ -729,16 +761,16 @@
cssom::RulesWithCascadePrecedence* matching_rules,
cssom::GURLMap* property_key_to_base_url_map,
const scoped_refptr<const cssom::CSSDeclaredStyleData>& inline_style,
- const scoped_refptr<const cssom::CSSComputedStyleData>&
- parent_computed_style,
+ const scoped_refptr<cssom::CSSComputedStyleDeclaration>&
+ parent_computed_style_declaration,
const scoped_refptr<const cssom::CSSComputedStyleData>& root_computed_style,
const math::Size& viewport_size,
const base::TimeDelta& style_change_event_time,
- cssom::TransitionSet* css_transitions,
const scoped_refptr<const cssom::CSSComputedStyleData>&
previous_computed_style,
- cssom::AnimationSet* css_animations,
- const cssom::CSSKeyframesRule::NameMap& keyframes_map) {
+ cssom::TransitionSet* css_transitions, cssom::AnimationSet* css_animations,
+ const cssom::CSSKeyframesRule::NameMap& keyframes_map,
+ bool* animations_modified) {
// Select the winning value for each property by performing the cascade,
// that is, apply values from matching rules on top of inline style, taking
// into account rule specificity and location in the source file, as well as
@@ -754,9 +786,9 @@
// properties, like "font-family", computed value is the same as specified
// value. Declarations that cannot be absolutized easily, like "width: auto;",
// will be resolved during layout.
- cssom::PromoteToComputedStyle(computed_style, parent_computed_style,
- root_computed_style, viewport_size,
- property_key_to_base_url_map);
+ cssom::PromoteToComputedStyle(
+ computed_style, parent_computed_style_declaration, root_computed_style,
+ viewport_size, property_key_to_base_url_map);
if (previous_computed_style) {
// Now that we have updated our computed style, compare it to the previous
@@ -764,13 +796,39 @@
css_transitions->UpdateTransitions(
style_change_event_time, *previous_computed_style, *computed_style);
}
- // Update the set of currently running animations.
- css_animations->Update(style_change_event_time, *computed_style,
- keyframes_map);
+ // Update the set of currently running animations and track whether or not the
+ // animations changed.
+ *animations_modified = css_animations->Update(style_change_event_time,
+ *computed_style, keyframes_map);
return computed_style;
}
+// Flags tracking which cached values must be invalidated.
+struct UpdateComputedStyleInvalidationFlags {
+ UpdateComputedStyleInvalidationFlags()
+ : invalidate_descendant_computed_styles(false),
+ invalidate_layout_boxes(false),
+ invalidate_sizes(false),
+ invalidate_cross_references(false),
+ invalidate_render_tree_nodes(false) {}
+
+ bool invalidate_descendant_computed_styles;
+ bool invalidate_layout_boxes;
+ bool invalidate_sizes;
+ bool invalidate_cross_references;
+ bool invalidate_render_tree_nodes;
+};
+
+bool NewComputedStyleInvalidatesDescendantComputedStyles(
+ const scoped_refptr<const cssom::CSSComputedStyleData>& old_computed_style,
+ const scoped_refptr<cssom::CSSComputedStyleData>& new_computed_style) {
+ return !non_trivial_static_fields.Get()
+ .computed_style_invalidation_property_checker
+ .DoDeclaredPropertiesMatch(old_computed_style,
+ new_computed_style);
+}
+
bool NewComputedStyleInvalidatesLayoutBoxes(
const scoped_refptr<const cssom::CSSComputedStyleData>& old_computed_style,
const scoped_refptr<cssom::CSSComputedStyleData>& new_computed_style) {
@@ -797,24 +855,82 @@
new_computed_style);
}
+void UpdateInvalidationFlagsForNewComputedStyle(
+ const scoped_refptr<const cssom::CSSComputedStyleData>& old_computed_style,
+ const scoped_refptr<cssom::CSSComputedStyleData>& new_computed_style,
+ bool animations_modified, UpdateComputedStyleInvalidationFlags* flags) {
+ if (old_computed_style) {
+ if (!flags->invalidate_descendant_computed_styles &&
+ NewComputedStyleInvalidatesDescendantComputedStyles(
+ old_computed_style, new_computed_style)) {
+ flags->invalidate_descendant_computed_styles = true;
+ flags->invalidate_layout_boxes = true;
+ } else if (!flags->invalidate_layout_boxes) {
+ if (NewComputedStyleInvalidatesLayoutBoxes(old_computed_style,
+ new_computed_style)) {
+ flags->invalidate_layout_boxes = true;
+ } else {
+ if (!flags->invalidate_sizes &&
+ NewComputedStyleInvalidatesSizes(old_computed_style,
+ new_computed_style)) {
+ flags->invalidate_sizes = true;
+ flags->invalidate_render_tree_nodes = true;
+ }
+ if (!flags->invalidate_cross_references &&
+ NewComputedStyleInvalidatesCrossReferences(old_computed_style,
+ new_computed_style)) {
+ flags->invalidate_cross_references = true;
+ flags->invalidate_render_tree_nodes = true;
+ }
+
+ flags->invalidate_render_tree_nodes =
+ flags->invalidate_render_tree_nodes || animations_modified ||
+ !new_computed_style->DoDeclaredPropertiesMatch(old_computed_style);
+ }
+ }
+ }
+}
+
} // namespace
void HTMLElement::UpdateComputedStyle(
- const scoped_refptr<const cssom::CSSComputedStyleData>&
- parent_computed_style,
+ const scoped_refptr<cssom::CSSComputedStyleDeclaration>&
+ parent_computed_style_declaration,
const scoped_refptr<const cssom::CSSComputedStyleData>& root_computed_style,
const base::TimeDelta& style_change_event_time) {
Document* document = node_document();
DCHECK(document) << "Element should be attached to document in order to "
"participate in layout.";
+ // If there is no previous computed style, there should also be no layout
+ // boxes.
+ DCHECK(computed_style() || NULL == layout_boxes());
+
dom_stat_tracker_->OnUpdateComputedStyle();
+ // The computed style must be generated if either the computed style is
+ // invalid or no computed style has been created yet.
+ bool generate_computed_style = !computed_style_valid_ || !computed_style();
+
// Update matching rules if necessary.
if (!matching_rules_valid_) {
dom_stat_tracker_->OnUpdateMatchingRules();
UpdateMatchingRules(this);
matching_rules_valid_ = true;
+
+ // Check for whether the matching rules have changed. If they have, then a
+ // new computed style must be generated from them.
+ if (!generate_computed_style && *old_matching_rules_ != *matching_rules_) {
+ generate_computed_style = true;
+ }
+ }
+
+ // If any declared properties inherited from the parent are no longer valid,
+ // then a new computed style must be generated with the updated inherited
+ // values.
+ if (!generate_computed_style &&
+ !computed_style()->AreDeclaredPropertiesInheritedFromParentValid()) {
+ generate_computed_style = true;
}
// TODO: It maybe helpful to generalize this mapping framework in the
@@ -824,95 +940,88 @@
property_key_to_base_url_map[cssom::kBackgroundImageProperty] =
document->url_as_gurl();
- scoped_refptr<cssom::CSSComputedStyleData> new_computed_style =
- PromoteMatchingRulesToComputedStyle(
- matching_rules(), &property_key_to_base_url_map, style_->data(),
- parent_computed_style, root_computed_style, document->viewport_size(),
- style_change_event_time, &css_transitions_, computed_style(),
- &css_animations_, document->keyframes_map());
+ // Flags tracking which cached values must be invalidated.
+ UpdateComputedStyleInvalidationFlags invalidation_flags;
- // If there is no previous computed style, there should also be no layout
- // boxes, and nothing has to be invalidated.
- bool invalidate_layout_boxes = false;
- bool invalidate_sizes = false;
- bool invalidate_cross_references = false;
+ if (generate_computed_style) {
+ bool animations_modified = false;
- DCHECK(computed_style() || NULL == layout_boxes());
- if (computed_style()) {
- if (NewComputedStyleInvalidatesLayoutBoxes(computed_style(),
- new_computed_style)) {
- invalidate_layout_boxes = true;
- } else {
- if (NewComputedStyleInvalidatesSizes(computed_style(),
- new_computed_style)) {
- invalidate_sizes = true;
- }
- if (NewComputedStyleInvalidatesCrossReferences(computed_style(),
- new_computed_style)) {
- invalidate_cross_references = true;
- }
- }
+ scoped_refptr<cssom::CSSComputedStyleData> new_computed_style =
+ PromoteMatchingRulesToComputedStyle(
+ matching_rules(), &property_key_to_base_url_map, style_->data(),
+ parent_computed_style_declaration, root_computed_style,
+ document->viewport_size(), style_change_event_time,
+ computed_style(), &css_transitions_, &css_animations_,
+ document->keyframes_map(), &animations_modified);
+
+ UpdateInvalidationFlagsForNewComputedStyle(
+ computed_style(), new_computed_style, animations_modified,
+ &invalidation_flags);
+
+ css_computed_style_declaration_->SetData(new_computed_style);
+
+ // Update cached background images after resolving the urls in
+ // background_image CSS property of the computed style, so we have all the
+ // information to get the cached background images.
+ UpdateCachedBackgroundImagesFromComputedStyle();
+ } else {
+ // Update the inherited data if a new style was not generated. The ancestor
+ // data with inherited properties may have changed.
+ css_computed_style_declaration_->UpdateInheritedData();
}
- set_computed_style(new_computed_style);
-
- // Update cached background images after resolving the urls in
- // background_image CSS property of the computed style, so we have all the
- // information to get the cached background images.
- UpdateCachedBackgroundImagesFromComputedStyle();
+ // NOTE: Currently, pseudo elements computed styles are always generated. If
+ // this becomes a performance bottleneck, change the logic so that it only
+ // occurs when needed.
// Promote the matching rules for all known pseudo elements.
for (int pseudo_element_type = 0; pseudo_element_type < kMaxPseudoElementType;
++pseudo_element_type) {
if (pseudo_elements_[pseudo_element_type]) {
+ bool animations_modified = false;
+
scoped_refptr<cssom::CSSComputedStyleData> pseudo_element_computed_style =
PromoteMatchingRulesToComputedStyle(
pseudo_elements_[pseudo_element_type]->matching_rules(),
- &property_key_to_base_url_map, style_->data(), computed_style(),
- root_computed_style, document->viewport_size(),
- style_change_event_time,
- pseudo_elements_[pseudo_element_type]->css_transitions(),
+ &property_key_to_base_url_map, style_->data(),
+ css_computed_style_declaration(), root_computed_style,
+ document->viewport_size(), style_change_event_time,
pseudo_elements_[pseudo_element_type]->computed_style(),
+ pseudo_elements_[pseudo_element_type]->css_transitions(),
pseudo_elements_[pseudo_element_type]->css_animations(),
- document->keyframes_map());
+ document->keyframes_map(), &animations_modified);
- if (!invalidate_layout_boxes &&
- pseudo_elements_[pseudo_element_type]->computed_style()) {
- if (NewComputedStyleInvalidatesLayoutBoxes(
- pseudo_elements_[pseudo_element_type]->computed_style(),
- pseudo_element_computed_style)) {
- invalidate_layout_boxes = true;
- } else {
- if (!invalidate_sizes &&
- NewComputedStyleInvalidatesSizes(
- pseudo_elements_[pseudo_element_type]->computed_style(),
- pseudo_element_computed_style)) {
- invalidate_sizes = true;
- }
- if (!invalidate_cross_references &&
- NewComputedStyleInvalidatesCrossReferences(
- pseudo_elements_[pseudo_element_type]->computed_style(),
- pseudo_element_computed_style)) {
- invalidate_cross_references = true;
- }
- }
- }
- pseudo_elements_[pseudo_element_type]->set_computed_style(
- pseudo_element_computed_style);
+ UpdateInvalidationFlagsForNewComputedStyle(
+ pseudo_elements_[pseudo_element_type]->computed_style(),
+ pseudo_element_computed_style, animations_modified,
+ &invalidation_flags);
+
+ pseudo_elements_[pseudo_element_type]
+ ->css_computed_style_declaration()
+ ->SetData(pseudo_element_computed_style);
}
}
- if (invalidate_layout_boxes) {
+ if (invalidation_flags.invalidate_descendant_computed_styles) {
+ InvalidateComputedStylesRecursively();
+ }
+
+ if (invalidation_flags.invalidate_layout_boxes) {
InvalidateLayoutBoxesFromNodeAndAncestors();
InvalidateLayoutBoxesFromNodeAndDescendants();
} else {
- if (invalidate_sizes) {
+ if (invalidation_flags.invalidate_sizes) {
InvalidateLayoutBoxSizesFromNode();
}
- if (invalidate_cross_references) {
+ if (invalidation_flags.invalidate_cross_references) {
InvalidateLayoutBoxCrossReferencesFromNode();
}
+ if (invalidation_flags.invalidate_render_tree_nodes) {
+ InvalidateRenderTreeNodesFromNode();
+ }
}
+
+ computed_style_valid_ = true;
}
void HTMLElement::UpdateCachedBackgroundImagesFromComputedStyle() {
diff --git a/src/cobalt/dom/html_element.h b/src/cobalt/dom/html_element.h
index eb6995f..11837a8 100644
--- a/src/cobalt/dom/html_element.h
+++ b/src/cobalt/dom/html_element.h
@@ -178,7 +178,7 @@
//
// Returns the cached matching rules of this element.
cssom::RulesWithCascadePrecedence* matching_rules() {
- return &matching_rules_;
+ return matching_rules_.get();
}
// Returns the rule matching state of this element.
RuleMatchingState* rule_matching_state() { return &rule_matching_state_; }
@@ -199,13 +199,12 @@
const {
return css_computed_style_declaration_->data();
}
- void set_computed_style(
- const scoped_refptr<cssom::CSSComputedStyleData>& computed_style) {
- css_computed_style_declaration_->set_data(computed_style);
- }
+
+ // Invalidates the cached computed style of this element and its descendants.
+ void InvalidateComputedStylesRecursively();
// Updates the cached computed style of this element and its descendants.
void UpdateComputedStyleRecursively(
- const scoped_refptr<const cssom::CSSComputedStyleData>&
+ const scoped_refptr<cssom::CSSComputedStyleDeclaration>&
parent_computed_style,
const scoped_refptr<const cssom::CSSComputedStyleData>&
root_computed_style,
@@ -213,8 +212,8 @@
bool ancestors_were_valid);
// Updates the cached computed style of this element.
void UpdateComputedStyle(
- const scoped_refptr<const cssom::CSSComputedStyleData>&
- parent_computed_style,
+ const scoped_refptr<cssom::CSSComputedStyleDeclaration>&
+ parent_computed_style_declaration,
const scoped_refptr<const cssom::CSSComputedStyleData>&
root_computed_style,
const base::TimeDelta& style_change_event_time);
@@ -233,6 +232,7 @@
void InvalidateLayoutBoxesFromNodeAndDescendants() OVERRIDE;
void InvalidateLayoutBoxSizesFromNode() OVERRIDE;
void InvalidateLayoutBoxCrossReferencesFromNode() OVERRIDE;
+ void InvalidateRenderTreeNodesFromNode() OVERRIDE;
// Determines whether this element is focusable.
bool IsFocusable() const { return HasAttribute("tabindex"); }
@@ -313,7 +313,8 @@
cssom::AnimationSet css_animations_;
// The following fields are used in rule matching.
- cssom::RulesWithCascadePrecedence matching_rules_;
+ scoped_ptr<cssom::RulesWithCascadePrecedence> old_matching_rules_;
+ scoped_ptr<cssom::RulesWithCascadePrecedence> matching_rules_;
RuleMatchingState rule_matching_state_;
// This contains information about the boxes generated from the element.
diff --git a/src/cobalt/dom/html_element_test.cc b/src/cobalt/dom/html_element_test.cc
index ce2a589..1e8bceb 100644
--- a/src/cobalt/dom/html_element_test.cc
+++ b/src/cobalt/dom/html_element_test.cc
@@ -86,6 +86,7 @@
MOCK_METHOD0(InvalidateSizes, void());
MOCK_METHOD0(InvalidateCrossReferences, void());
+ MOCK_METHOD0(InvalidateRenderTreeNodes, void());
};
// Takes the fist child of the given element repeatedly to the given depth.
@@ -136,7 +137,7 @@
document_->CreateElement(*null_terminated_element_names)
->AsHTMLElement());
DCHECK(child_html_element);
- child_html_element->set_computed_style(
+ child_html_element->css_computed_style_declaration()->SetData(
make_scoped_refptr(new cssom::CSSComputedStyleData()));
if (parent_html_element) {
@@ -442,7 +443,8 @@
make_scoped_refptr(new cssom::CSSComputedStyleData());
computed_style_relative->set_position(cssom::KeywordValue::GetRelative());
GetFirstChildAtDepth(root_html_element, 2)
- ->set_computed_style(computed_style_relative);
+ ->css_computed_style_declaration()
+ ->SetData(computed_style_relative);
// Return ancestor if it is the HTML body element.
EXPECT_EQ(GetFirstChildAtDepth(root_html_element, 2)->offset_parent(),
@@ -454,7 +456,8 @@
make_scoped_refptr(new cssom::CSSComputedStyleData());
computed_style_fixed->set_position(cssom::KeywordValue::GetFixed());
GetFirstChildAtDepth(root_html_element, 3)
- ->set_computed_style(computed_style_fixed);
+ ->css_computed_style_declaration()
+ ->SetData(computed_style_fixed);
EXPECT_FALSE(GetFirstChildAtDepth(root_html_element, 3)->offset_parent());
// Return ancestor if its computed value of the 'position' property is not
diff --git a/src/cobalt/dom/html_video_element.cc b/src/cobalt/dom/html_video_element.cc
index b7e4751..89d0f1e 100644
--- a/src/cobalt/dom/html_video_element.cc
+++ b/src/cobalt/dom/html_video_element.cc
@@ -71,6 +71,17 @@
return static_cast<uint32>(player()->GetNaturalSize().height());
}
+scoped_refptr<VideoPlaybackQuality> HTMLVideoElement::GetVideoPlaybackQuality()
+ const {
+ // TODO: Provide all attributes with valid values.
+ return new VideoPlaybackQuality(
+ 0., // creation_time
+ player() ? static_cast<uint32>(player()->GetDecodedFrameCount()) : 0,
+ player() ? static_cast<uint32>(player()->GetDroppedFrameCount()) : 0,
+ 0, // corrupted_video_frames
+ 0.); // total_frame_delay
+}
+
scoped_refptr<ShellVideoFrameProvider>
HTMLVideoElement::GetVideoFrameProvider() {
DCHECK(thread_checker_.CalledOnValidThread());
diff --git a/src/cobalt/dom/html_video_element.h b/src/cobalt/dom/html_video_element.h
index 0f83f04..2ac5c3f 100644
--- a/src/cobalt/dom/html_video_element.h
+++ b/src/cobalt/dom/html_video_element.h
@@ -20,6 +20,7 @@
#include <string>
#include "cobalt/dom/html_media_element.h"
+#include "cobalt/dom/video_playback_quality.h"
#include "media/base/shell_video_frame_provider.h"
namespace cobalt {
@@ -43,6 +44,7 @@
void set_height(uint32 height);
uint32 video_width() const;
uint32 video_height() const;
+ scoped_refptr<VideoPlaybackQuality> GetVideoPlaybackQuality() const;
// Custom, not in any spec
//
diff --git a/src/cobalt/dom/layout_boxes.h b/src/cobalt/dom/layout_boxes.h
index 350a7cc..98eccce 100644
--- a/src/cobalt/dom/layout_boxes.h
+++ b/src/cobalt/dom/layout_boxes.h
@@ -81,6 +81,8 @@
// Invalidate the cross references, which relates to both positioned children
// of containing blocks and z-index children of stacking contexts.
virtual void InvalidateCrossReferences() = 0;
+ // Invalidate the layout box's render tree nodes.
+ virtual void InvalidateRenderTreeNodes() = 0;
protected:
LayoutBoxes() {}
diff --git a/src/cobalt/dom/node.h b/src/cobalt/dom/node.h
index ceee672..0b2ca54 100644
--- a/src/cobalt/dom/node.h
+++ b/src/cobalt/dom/node.h
@@ -239,6 +239,8 @@
virtual void InvalidateLayoutBoxSizesFromNode() {}
// Invalidate the cross references within the layout boxes of this node.
virtual void InvalidateLayoutBoxCrossReferencesFromNode() {}
+ // Invalidate the render tree nodes within the layout boxes of this node.
+ virtual void InvalidateRenderTreeNodesFromNode() {}
// Triggers a generation update in this node and all its ancestor nodes.
void UpdateGenerationForNodeAndAncestors();
diff --git a/src/cobalt/dom/pseudo_element.h b/src/cobalt/dom/pseudo_element.h
index 0531421..18e94d7 100644
--- a/src/cobalt/dom/pseudo_element.h
+++ b/src/cobalt/dom/pseudo_element.h
@@ -58,10 +58,6 @@
scoped_refptr<const cssom::CSSComputedStyleData> computed_style() const {
return css_computed_style_declaration_->data();
}
- void set_computed_style(
- const scoped_refptr<const cssom::CSSComputedStyleData>& computed_style) {
- css_computed_style_declaration_->set_data(computed_style);
- }
cssom::RulesWithCascadePrecedence* matching_rules() {
return &matching_rules_;
diff --git a/src/cobalt/dom/video_playback_quality.h b/src/cobalt/dom/video_playback_quality.h
new file mode 100644
index 0000000..e5e88e3
--- /dev/null
+++ b/src/cobalt/dom/video_playback_quality.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2016 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.
+ */
+
+#ifndef COBALT_DOM_VIDEO_PLAYBACK_QUALITY_H_
+#define COBALT_DOM_VIDEO_PLAYBACK_QUALITY_H_
+
+#include "base/basictypes.h"
+#include "cobalt/script/wrappable.h"
+
+namespace cobalt {
+namespace dom {
+
+// The VideoPlaybackQuality interface exposes data to describe the video
+// playback quality.
+// https://www.w3.org/TR/media-source/#idl-def-VideoPlaybackQuality
+class VideoPlaybackQuality : public script::Wrappable {
+ public:
+ VideoPlaybackQuality(double creation_time, uint32 total_video_frames,
+ uint32 dropped_video_frames,
+ uint32 corrupted_video_frames, double total_frame_delay)
+ : creation_time_(creation_time),
+ total_video_frames_(total_video_frames),
+ dropped_video_frames_(dropped_video_frames),
+ corrupted_video_frames_(corrupted_video_frames),
+ total_frame_delay_(total_frame_delay) {}
+
+ // Web API: VideoPlaybackQuality
+ //
+ double creation_time() const { return creation_time_; }
+ uint32 total_video_frames() const { return total_video_frames_; }
+ uint32 dropped_video_frames() const { return dropped_video_frames_; }
+ uint32 corrupted_video_frames() const { return corrupted_video_frames_; }
+ double total_frame_delay() const { return total_frame_delay_; }
+
+ DEFINE_WRAPPABLE_TYPE(VideoPlaybackQuality);
+
+ private:
+ double creation_time_;
+ uint32 total_video_frames_;
+ uint32 dropped_video_frames_;
+ uint32 corrupted_video_frames_;
+ double total_frame_delay_;
+};
+
+} // namespace dom
+} // namespace cobalt
+
+#endif // COBALT_DOM_VIDEO_PLAYBACK_QUALITY_H_
diff --git a/src/cobalt/dom/window.cc b/src/cobalt/dom/window.cc
index e1f7bce..cdab450 100644
--- a/src/cobalt/dom/window.cc
+++ b/src/cobalt/dom/window.cc
@@ -90,7 +90,7 @@
ALLOW_THIS_IN_INITIALIZER_LIST(document_(new Document(
html_element_context_.get(),
Document::Options(
- url,
+ url, this,
base::Bind(&Window::FireHashChangeEvent, base::Unretained(this)),
performance_->timing()->GetNavigationStartClock(),
navigation_callback, ParseUserAgentStyleSheet(css_parser),
diff --git a/src/cobalt/dom/window_timers.cc b/src/cobalt/dom/window_timers.cc
index 04e58b8..df784cd 100644
--- a/src/cobalt/dom/window_timers.cc
+++ b/src/cobalt/dom/window_timers.cc
@@ -73,7 +73,10 @@
void WindowTimers::RunTimerCallback(int handle) {
Timers::iterator timer = timers_.find(handle);
DCHECK(timer != timers_.end());
- timer->second->callback_reference().value().Run();
+ // Keep a |TimerInfo| reference, so it won't be released when running the
+ // callback.
+ scoped_refptr<TimerInfo> timer_info = timer->second;
+ timer_info->callback_reference().value().Run();
// After running the callback, double check whether the timer is still there
// since it might be deleted inside the callback.
timer = timers_.find(handle);
diff --git a/src/cobalt/layout/anonymous_block_box.cc b/src/cobalt/layout/anonymous_block_box.cc
index b20e597..281cc70 100644
--- a/src/cobalt/layout/anonymous_block_box.cc
+++ b/src/cobalt/layout/anonymous_block_box.cc
@@ -62,11 +62,8 @@
}
void AnonymousBlockBox::RenderAndAnimateContent(
- render_tree::CompositionNode::Builder* border_node_builder,
- render_tree::animations::NodeAnimationsMap::Builder*
- node_animations_map_builder) const {
- ContainerBox::RenderAndAnimateContent(border_node_builder,
- node_animations_map_builder);
+ render_tree::CompositionNode::Builder* border_node_builder) const {
+ ContainerBox::RenderAndAnimateContent(border_node_builder);
if (computed_style()->visibility() != cssom::KeywordValue::GetVisible()) {
return;
@@ -125,24 +122,20 @@
scoped_ptr<FormattingContext> AnonymousBlockBox::UpdateRectOfInFlowChildBoxes(
const LayoutParams& child_layout_params) {
- // Check to see if ellipses are enabled:
- // If they are, then retrieve the ellipsis width for the font and reset the
- // ellipsis boxes on all child boxes because they are no longer valid.
- // Otherwise, set the width to 0, which indicates that ellipses are not being
- // used. In this case, child boxes do not need to have ellipses reset, as they
- // could not have previously been set.
- float ellipsis_width;
- if (AreEllipsesEnabled()) {
- ellipsis_width = used_font_->GetEllipsisWidth();
-
- for (Boxes::const_iterator child_box_iterator = child_boxes().begin();
- child_box_iterator != child_boxes().end(); ++child_box_iterator) {
- (*child_box_iterator)->ResetEllipses();
- }
- } else {
- ellipsis_width = 0;
+ // Do any processing needed prior to ellipsis placement on all of the
+ // children.
+ for (Boxes::const_iterator child_ellipsis_iterator = child_boxes().begin();
+ child_ellipsis_iterator != child_boxes().end();
+ ++child_ellipsis_iterator) {
+ (*child_ellipsis_iterator)->DoPreEllipsisPlacementProcessing();
}
+ // If ellipses are enabled then retrieve the ellipsis width for the font;
+ // otherwise, set the width to 0, which indicates that ellipses are not being
+ // used.
+ float ellipsis_width =
+ AreEllipsesEnabled() ? used_font_->GetEllipsisWidth() : 0;
+
// Lay out child boxes in the normal flow.
// https://www.w3.org/TR/CSS21/visuren.html#normal-flow
scoped_ptr<InlineFormattingContext> inline_formatting_context(
@@ -204,6 +197,15 @@
}
inline_formatting_context->EndUpdates();
ellipses_coordinates_ = inline_formatting_context->GetEllipsesCoordinates();
+
+ // Do any processing needed following ellipsis placement on all of the
+ // children.
+ for (Boxes::const_iterator child_ellipsis_iterator = child_boxes().begin();
+ child_ellipsis_iterator != child_boxes().end();
+ ++child_ellipsis_iterator) {
+ (*child_ellipsis_iterator)->DoPostEllipsisPlacementProcessing();
+ }
+
return inline_formatting_context.PassAs<FormattingContext>();
}
diff --git a/src/cobalt/layout/anonymous_block_box.h b/src/cobalt/layout/anonymous_block_box.h
index 54c1673..bda736f 100644
--- a/src/cobalt/layout/anonymous_block_box.h
+++ b/src/cobalt/layout/anonymous_block_box.h
@@ -47,10 +47,8 @@
bool HasTrailingLineBreak() const OVERRIDE;
- void RenderAndAnimateContent(
- render_tree::CompositionNode::Builder* border_node_builder,
- render_tree::animations::NodeAnimationsMap::Builder*
- node_animations_map_builder) const OVERRIDE;
+ void RenderAndAnimateContent(render_tree::CompositionNode::Builder*
+ border_node_builder) const OVERRIDE;
// From |ContainerBox|.
diff --git a/src/cobalt/layout/block_formatting_block_container_box.cc b/src/cobalt/layout/block_formatting_block_container_box.cc
index b4023d8..1c85502 100644
--- a/src/cobalt/layout/block_formatting_block_container_box.cc
+++ b/src/cobalt/layout/block_formatting_block_container_box.cc
@@ -96,14 +96,14 @@
// TODO: Determine which animations to propagate to the anonymous block box,
// instead of none at all.
scoped_refptr<cssom::CSSComputedStyleDeclaration>
- css_computed_style_declaration =
+ new_computed_style_declaration =
new cssom::CSSComputedStyleDeclaration();
- css_computed_style_declaration->set_data(
- GetComputedStyleOfAnonymousBox(computed_style()));
- css_computed_style_declaration->set_animations(
+ new_computed_style_declaration->SetData(
+ GetComputedStyleOfAnonymousBox(css_computed_style_declaration()));
+ new_computed_style_declaration->set_animations(
new web_animations::AnimationSet());
scoped_refptr<AnonymousBlockBox> new_anonymous_block_box(
- new AnonymousBlockBox(css_computed_style_declaration,
+ new AnonymousBlockBox(new_computed_style_declaration,
GetBaseDirection(), used_style_provider(),
layout_stat_tracker()));
anonymous_block_box = new_anonymous_block_box.get();
@@ -144,7 +144,8 @@
layout_stat_tracker),
paragraph_(paragraph),
text_position_(text_position),
- is_hidden_by_ellipsis_(false) {}
+ is_hidden_by_ellipsis_(false),
+ was_hidden_by_ellipsis_(false) {}
InlineLevelBlockContainerBox::~InlineLevelBlockContainerBox() {}
@@ -216,10 +217,17 @@
return true;
}
-void InlineLevelBlockContainerBox::ResetEllipses() {
+void InlineLevelBlockContainerBox::DoPreEllipsisPlacementProcessing() {
+ was_hidden_by_ellipsis_ = is_hidden_by_ellipsis_;
is_hidden_by_ellipsis_ = false;
}
+void InlineLevelBlockContainerBox::DoPostEllipsisPlacementProcessing() {
+ if (was_hidden_by_ellipsis_ != is_hidden_by_ellipsis_) {
+ InvalidateRenderTreeNodesOfBoxAndAncestors();
+ }
+}
+
bool InlineLevelBlockContainerBox::IsHiddenByEllipsis() const {
return is_hidden_by_ellipsis_;
}
diff --git a/src/cobalt/layout/block_formatting_block_container_box.h b/src/cobalt/layout/block_formatting_block_container_box.h
index 197960b..a4a5bd9 100644
--- a/src/cobalt/layout/block_formatting_block_container_box.h
+++ b/src/cobalt/layout/block_formatting_block_container_box.h
@@ -117,7 +117,8 @@
base::optional<int> GetBidiLevel() const OVERRIDE;
bool DoesFulfillEllipsisPlacementRequirement() const OVERRIDE;
- void ResetEllipses() OVERRIDE;
+ void DoPreEllipsisPlacementProcessing() OVERRIDE;
+ void DoPostEllipsisPlacementProcessing() OVERRIDE;
bool IsHiddenByEllipsis() const OVERRIDE;
protected:
@@ -143,6 +144,11 @@
// the applicable edge(s) of the line as necessary to fit the ellipsis."
// https://www.w3.org/TR/css3-ui/#propdef-text-overflow
bool is_hidden_by_ellipsis_;
+ // Tracking of the previous value of |is_hidden_by_ellipsis_|, which allows
+ // for determination of whether or not the value changed during ellipsis
+ // placement. When this occurs, the cached render tree nodes of this box and
+ // its ancestors are invalidated.
+ bool was_hidden_by_ellipsis_;
};
} // namespace layout
diff --git a/src/cobalt/layout/box.cc b/src/cobalt/layout/box.cc
index 82cbeb3..c8739ee 100644
--- a/src/cobalt/layout/box.cc
+++ b/src/cobalt/layout/box.cc
@@ -53,7 +53,7 @@
using cobalt::render_tree::RoundedCorners;
using cobalt::render_tree::ViewportFilter;
using cobalt::render_tree::animations::Animation;
-using cobalt::render_tree::animations::NodeAnimationsMap;
+using cobalt::render_tree::animations::AnimateNode;
namespace cobalt {
namespace layout {
@@ -110,6 +110,10 @@
UpdateBorders();
UpdatePaddings(layout_params);
UpdateContentSizeAndMargins(layout_params);
+
+ // After a size update, this portion of the render tree must be updated, so
+ // invalidate any cached render tree nodes.
+ InvalidateRenderTreeNodesOfBoxAndAncestors();
}
bool Box::ValidateUpdateSizeInputs(const LayoutParams& params) {
@@ -190,6 +194,13 @@
}
}
+void Box::InvalidateRenderTreeNodesOfBoxAndAncestors() {
+ cached_render_tree_node_info_ = base::nullopt;
+ if (parent_) {
+ parent_->InvalidateRenderTreeNodesOfBoxAndAncestors();
+ }
+}
+
LayoutUnit Box::GetMarginBoxWidth() const {
return margin_left() + GetBorderBoxWidth() + margin_right();
}
@@ -385,8 +396,25 @@
void Box::RenderAndAnimate(
CompositionNode::Builder* parent_content_node_builder,
- NodeAnimationsMap::Builder* node_animations_map_builder,
- const math::Vector2dF& offset_from_parent_node) const {
+ const math::Vector2dF& offset_from_parent_node) {
+ math::Vector2dF border_box_offset(left().toFloat() + margin_left().toFloat(),
+ top().toFloat() + margin_top().toFloat());
+ border_box_offset += offset_from_parent_node;
+
+ // If there's a pre-existing cached render tree node that is located at the
+ // border box offset, then simply use it. There's no more work to do.
+ if (cached_render_tree_node_info_ &&
+ cached_render_tree_node_info_->offset_ == border_box_offset) {
+ if (cached_render_tree_node_info_->node_) {
+ parent_content_node_builder->AddChild(
+ cached_render_tree_node_info_->node_);
+ }
+ return;
+ }
+
+ // Initialize the cached render tree node with the border box offset.
+ cached_render_tree_node_info_ = CachedRenderTreeNodeInfo(border_box_offset);
+
float opacity = base::polymorphic_downcast<const cssom::NumberValue*>(
computed_style()->opacity().get())
->value();
@@ -406,10 +434,8 @@
return;
}
- math::Vector2dF border_box_offset(left().toFloat() + margin_left().toFloat(),
- top().toFloat() + margin_top().toFloat());
- border_box_offset += offset_from_parent_node;
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);
@@ -446,17 +472,14 @@
// 'visibility: visible'.
// https://www.w3.org/TR/CSS21/visufx.html#propdef-visibility
if (computed_style()->visibility() == cssom::KeywordValue::GetVisible()) {
- RenderAndAnimateBackgroundColor(padding_rounded_corners,
- &border_node_builder,
- node_animations_map_builder);
- RenderAndAnimateBackgroundImage(padding_rounded_corners,
- &border_node_builder,
- node_animations_map_builder);
+ RenderAndAnimateBackgroundColor(
+ padding_rounded_corners, &border_node_builder, &animate_node_builder);
+ RenderAndAnimateBackgroundImage(
+ padding_rounded_corners, &border_node_builder, &animate_node_builder);
RenderAndAnimateBorder(border_radius_provider.rounded_corners(),
- &border_node_builder, node_animations_map_builder);
+ &border_node_builder, &animate_node_builder);
RenderAndAnimateBoxShadow(border_radius_provider.rounded_corners(),
- &border_node_builder,
- node_animations_map_builder);
+ &border_node_builder, &animate_node_builder);
}
const bool overflow_hidden =
@@ -472,17 +495,17 @@
border_insets_.zero())) {
// If there's no reason to distinguish between content and background,
// just add them all to the same composition node.
- RenderAndAnimateContent(&border_node_builder, node_animations_map_builder);
+ RenderAndAnimateContent(&border_node_builder);
} else {
CompositionNode::Builder content_node_builder;
// Otherwise, deal with content specifically so that we can apply overflow:
// hidden to the content but not the background.
- RenderAndAnimateContent(&content_node_builder, node_animations_map_builder);
+ RenderAndAnimateContent(&content_node_builder);
if (!content_node_builder.children().empty()) {
border_node_builder.AddChild(RenderAndAnimateOverflow(
padding_rounded_corners,
new CompositionNode(content_node_builder.Pass()),
- node_animations_map_builder, math::Vector2dF(0, 0)));
+ &animate_node_builder, math::Vector2dF(0, 0)));
}
// We've already applied overflow hidden, no need to apply it again later.
overflow_hidden_needs_to_be_applied = false;
@@ -492,16 +515,22 @@
scoped_refptr<render_tree::Node> border_node =
new CompositionNode(border_node_builder.Pass());
if (overflow_hidden_needs_to_be_applied) {
- border_node = RenderAndAnimateOverflow(
- padding_rounded_corners, border_node, node_animations_map_builder,
- border_box_offset);
+ border_node =
+ RenderAndAnimateOverflow(padding_rounded_corners, border_node,
+ &animate_node_builder, border_box_offset);
}
- border_node = RenderAndAnimateOpacity(
- border_node, node_animations_map_builder, opacity, opacity_animated);
- border_node = RenderAndAnimateTransform(
- border_node, node_animations_map_builder, border_box_offset);
+ border_node = RenderAndAnimateOpacity(border_node, &animate_node_builder,
+ opacity, opacity_animated);
+ border_node = RenderAndAnimateTransform(border_node, &animate_node_builder,
+ border_box_offset);
- parent_content_node_builder->AddChild(border_node);
+ cached_render_tree_node_info_->node_ =
+ animate_node_builder.empty()
+ ? border_node
+ : scoped_refptr<render_tree::Node>(
+ new AnimateNode(animate_node_builder, border_node));
+
+ parent_content_node_builder->AddChild(cached_render_tree_node_info_->node_);
}
}
@@ -536,6 +565,14 @@
#endif // COBALT_BOX_DUMP_ENABLED
namespace {
+void PopulateBaseStyleForBackgroundNode(
+ const scoped_refptr<const cssom::CSSComputedStyleData>& source_style,
+ const scoped_refptr<cssom::CSSComputedStyleData>& destination_style) {
+ // NOTE: Properties set by PopulateBaseStyleForBackgroundNode() should match
+ // the properties used by SetupBackgroundNodeFromStyle().
+ destination_style->set_background_color(source_style->background_color());
+}
+
void SetupBackgroundNodeFromStyle(
const base::optional<RoundedCorners>& rounded_corners,
const scoped_refptr<const cssom::CSSComputedStyleData>& style,
@@ -596,6 +633,36 @@
return Border(left, right, top, bottom);
}
+void PopulateBaseStyleForBorderNode(
+ const scoped_refptr<const cssom::CSSComputedStyleData>& source_style,
+ const scoped_refptr<cssom::CSSComputedStyleData>& destination_style) {
+ // NOTE: Properties set by PopulateBaseStyleForBorderNode() should match the
+ // properties used by SetupBorderNodeFromStyle().
+
+ // Left
+ destination_style->set_border_left_width(source_style->border_left_width());
+ destination_style->set_border_left_style(source_style->border_left_style());
+ destination_style->set_border_left_color(source_style->border_left_color());
+
+ // Right
+ destination_style->set_border_right_width(source_style->border_right_width());
+ destination_style->set_border_right_style(source_style->border_right_style());
+ destination_style->set_border_right_color(source_style->border_right_color());
+
+ // Top
+ destination_style->set_border_top_width(source_style->border_top_width());
+ destination_style->set_border_top_style(source_style->border_top_style());
+ destination_style->set_border_top_color(source_style->border_top_color());
+
+ // Bottom
+ destination_style->set_border_bottom_width(
+ source_style->border_bottom_width());
+ destination_style->set_border_bottom_style(
+ source_style->border_bottom_style());
+ destination_style->set_border_bottom_color(
+ source_style->border_bottom_color());
+}
+
void SetupBorderNodeFromStyle(
const base::optional<RoundedCorners>& rounded_corners,
const scoped_refptr<const cssom::CSSComputedStyleData>& style,
@@ -774,7 +841,7 @@
// CSS transform style property. If the object does not have a transform
// style property set, this will be the identity matrix. Otherwise, it is
// calculated from the property value and returned. The transform-origin
-// style property will also be taken into account, and therefore the layed
+// style property will also be taken into account, and therefore the laid
// out size of the object is also required in order to resolve a
// percentage-based transform-origin.
math::Matrix3F GetCSSTransform(
@@ -797,10 +864,20 @@
math::TranslateMatrix(-origin.x(), -origin.y());
}
-// Used within the animation callback for CSS transforms. This will
-// set the transform of a single-child composition node to that specified by
-// the CSS transform of the provided CSS Style Declaration.
-void SetupCompositionNodeFromCSSSStyleTransform(
+void PopulateBaseStyleForMatrixTransformNode(
+ const scoped_refptr<const cssom::CSSComputedStyleData>& source_style,
+ const scoped_refptr<cssom::CSSComputedStyleData>& destination_style) {
+ // NOTE: Properties set by PopulateBaseStyleForMatrixTransformNode() should
+ // match the properties used by
+ // SetupMatrixTransformNodeFromCSSSStyleTransform().
+ destination_style->set_transform(source_style->transform());
+ destination_style->set_transform_origin(source_style->transform_origin());
+}
+
+// Used within the animation callback for CSS transforms. This will set the
+// transform of a single-child matrix transform node to that specified by the
+// CSS transform of the provided CSS Style Declaration.
+void SetupMatrixTransformNodeFromCSSSStyleTransform(
const math::RectF& used_rect,
const scoped_refptr<const cssom::CSSComputedStyleData>& style,
MatrixTransformNode::Builder* transform_node_builder) {
@@ -808,6 +885,14 @@
GetCSSTransform(style->transform(), style->transform_origin(), used_rect);
}
+void PopulateBaseStyleForFilterNode(
+ const scoped_refptr<const cssom::CSSComputedStyleData>& source_style,
+ const scoped_refptr<cssom::CSSComputedStyleData>& destination_style) {
+ // NOTE: Properties set by PopulateBaseStyleForFilterNode() should match the
+ // properties used by SetupFilterNodeFromStyle().
+ destination_style->set_opacity(source_style->opacity());
+}
+
void SetupFilterNodeFromStyle(
const scoped_refptr<const cssom::CSSComputedStyleData>& style,
FilterNode::Builder* filter_node_builder) {
@@ -843,8 +928,8 @@
void Box::RenderAndAnimateBoxShadow(
const base::optional<RoundedCorners>& rounded_corners,
CompositionNode::Builder* border_node_builder,
- NodeAnimationsMap::Builder* node_animations_map_builder) const {
- UNREFERENCED_PARAMETER(node_animations_map_builder);
+ AnimateNode::Builder* animate_node_builder) {
+ UNREFERENCED_PARAMETER(animate_node_builder);
if (computed_style()->box_shadow() != cssom::KeywordValue::GetNone()) {
const cssom::PropertyListValue* box_shadow_list =
@@ -907,7 +992,7 @@
void Box::RenderAndAnimateBorder(
const base::optional<RoundedCorners>& rounded_corners,
CompositionNode::Builder* border_node_builder,
- NodeAnimationsMap::Builder* node_animations_map_builder) const {
+ AnimateNode::Builder* animate_node_builder) {
// If the border is absent or all borders are transparent, there is no need
// to render border.
if (border_insets_.zero() || AreAllBordersTransparent(computed_style())) {
@@ -924,16 +1009,16 @@
if (HasAnimatedBorder(animations())) {
AddAnimations<RectNode>(
+ base::Bind(&PopulateBaseStyleForBorderNode),
base::Bind(&SetupBorderNodeFromStyle, rounded_corners),
- *css_computed_style_declaration(), border_node,
- node_animations_map_builder);
+ *css_computed_style_declaration(), border_node, animate_node_builder);
}
}
void Box::RenderAndAnimateBackgroundColor(
const base::optional<RoundedCorners>& rounded_corners,
render_tree::CompositionNode::Builder* border_node_builder,
- NodeAnimationsMap::Builder* node_animations_map_builder) const {
+ AnimateNode::Builder* animate_node_builder) {
// Only create the RectNode if the background color is not the initial value
// (which we know is transparent) and not transparent. If it's animated,
// add it no matter what since its value may change over time to be
@@ -958,9 +1043,9 @@
// instead here.
if (background_color_animated) {
AddAnimations<RectNode>(
+ base::Bind(&PopulateBaseStyleForBackgroundNode),
base::Bind(&SetupBackgroundNodeFromStyle, rounded_corners),
- *css_computed_style_declaration(), rect_node,
- node_animations_map_builder);
+ *css_computed_style_declaration(), rect_node, animate_node_builder);
}
}
}
@@ -969,8 +1054,8 @@
void Box::RenderAndAnimateBackgroundImage(
const base::optional<RoundedCorners>& rounded_corners,
CompositionNode::Builder* border_node_builder,
- NodeAnimationsMap::Builder* node_animations_map_builder) const {
- UNREFERENCED_PARAMETER(node_animations_map_builder);
+ AnimateNode::Builder* animate_node_builder) {
+ UNREFERENCED_PARAMETER(animate_node_builder);
math::RectF image_frame(
math::PointF(border_left_width().toFloat(), border_top_width().toFloat()),
@@ -1012,9 +1097,8 @@
scoped_refptr<render_tree::Node> Box::RenderAndAnimateOpacity(
const scoped_refptr<render_tree::Node>& border_node,
- render_tree::animations::NodeAnimationsMap::Builder*
- node_animations_map_builder,
- float opacity, bool opacity_animated) const {
+ AnimateNode::Builder* animate_node_builder, float opacity,
+ bool opacity_animated) {
if (opacity < 1.0f || opacity_animated) {
FilterNode::Builder filter_node_builder(border_node);
@@ -1026,9 +1110,10 @@
if (opacity_animated) {
// Possibly setup an animation for opacity.
- AddAnimations<FilterNode>(base::Bind(&SetupFilterNodeFromStyle),
+ AddAnimations<FilterNode>(base::Bind(&PopulateBaseStyleForFilterNode),
+ base::Bind(&SetupFilterNodeFromStyle),
*css_computed_style_declaration(), filter_node,
- node_animations_map_builder);
+ animate_node_builder);
}
return filter_node;
}
@@ -1038,10 +1123,9 @@
scoped_refptr<render_tree::Node> Box::RenderAndAnimateOverflow(
const base::optional<render_tree::RoundedCorners>& rounded_corners,
- const scoped_refptr<render_tree::Node>& content_node,
- render_tree::animations::NodeAnimationsMap::Builder*
- /* node_animations_map_builder */,
- const math::Vector2dF& border_node_offset) const {
+ const scoped_refptr<render_tree::Node>& content_node, AnimateNode::Builder*
+ /* animate_node_builder */,
+ const math::Vector2dF& border_node_offset) {
bool overflow_hidden =
computed_style()->overflow().get() == cssom::KeywordValue::GetHidden();
@@ -1069,24 +1153,25 @@
scoped_refptr<render_tree::Node> Box::RenderAndAnimateTransform(
const scoped_refptr<render_tree::Node>& border_node,
- render_tree::animations::NodeAnimationsMap::Builder*
- node_animations_map_builder,
- const math::Vector2dF& border_node_offset) const {
+ AnimateNode::Builder* animate_node_builder,
+ const math::Vector2dF& border_node_offset) {
if (IsTransformable() &&
animations()->IsPropertyAnimated(cssom::kTransformProperty)) {
// If the CSS transform is animated, we cannot flatten it into the layout
- // transform, thus we create a new composition node to separate it and
+ // transform, thus we create a new matrix transform node to separate it and
// animate that node only.
scoped_refptr<MatrixTransformNode> css_transform_node =
new MatrixTransformNode(border_node, math::Matrix3F::Identity());
- // Specifically animate only the composition node with the CSS transform.
+ // Specifically animate only the matrix transform node with the CSS
+ // transform.
AddAnimations<MatrixTransformNode>(
- base::Bind(&SetupCompositionNodeFromCSSSStyleTransform,
+ base::Bind(&PopulateBaseStyleForMatrixTransformNode),
+ base::Bind(&SetupMatrixTransformNodeFromCSSSStyleTransform,
math::RectF(PointAtOffsetFromOrigin(border_node_offset),
GetBorderBoxSize())),
*css_computed_style_declaration(), css_transform_node,
- node_animations_map_builder);
+ animate_node_builder);
return css_transform_node;
}
diff --git a/src/cobalt/layout/box.h b/src/cobalt/layout/box.h
index a85dfc5..676b04d 100644
--- a/src/cobalt/layout/box.h
+++ b/src/cobalt/layout/box.h
@@ -37,7 +37,7 @@
#include "cobalt/layout/vector2d_layout_unit.h"
#include "cobalt/math/point_f.h"
#include "cobalt/math/rect_f.h"
-#include "cobalt/render_tree/animations/node_animations_map.h"
+#include "cobalt/render_tree/animations/animate_node.h"
#include "cobalt/render_tree/composition_node.h"
#include "cobalt/web_animations/animation_set.h"
@@ -314,8 +314,15 @@
// element on a line."
// https://www.w3.org/TR/css3-ui/#propdef-text-overflow
virtual bool DoesFulfillEllipsisPlacementRequirement() const { return false; }
- // Reset all ellipses-related state within the box.
- virtual void ResetEllipses() {}
+ // Do any processing needed prior to ellipsis placement. This involves caching
+ // the old value and resetting the current value so it can be determined
+ // whether or not the ellipsis state within a box changed as a a result of
+ // ellipsis placement.
+ virtual void DoPreEllipsisPlacementProcessing() {}
+ // Do any processing needed following ellipsis placement. This involves
+ // checking the old value against the new value and resetting the cached
+ // render tree node if the ellipsis state changed.
+ virtual void DoPostEllipsisPlacementProcessing() {}
// Whether or not the box is fully hidden by an ellipsis. This applies to
// atomic inline-level elements that have had an ellipsis placed before them
// on a line. https://www.w3.org/TR/css3-ui/#propdef-text-overflow
@@ -401,14 +408,16 @@
// time they are needed.
virtual void InvalidateCrossReferencesOfBoxAndAncestors();
+ // Invalidating the render tree nodes causes them to be re-generated the next
+ // time they are needed.
+ void InvalidateRenderTreeNodesOfBoxAndAncestors();
+
// Converts a layout subtree into a render subtree.
// This method defines the overall strategy of the conversion and relies
// on the subclasses to provide the actual content.
void RenderAndAnimate(
render_tree::CompositionNode::Builder* parent_content_node_builder,
- render_tree::animations::NodeAnimationsMap::Builder*
- node_animations_map_builder,
- const math::Vector2dF& offset_from_parent_node) const;
+ const math::Vector2dF& offset_from_parent_node);
// Poor man's reflection.
virtual AnonymousBlockBox* AsAnonymousBlockBox();
@@ -528,9 +537,7 @@
// Renders the content of the box.
virtual void RenderAndAnimateContent(
- render_tree::CompositionNode::Builder* border_node_builder,
- render_tree::animations::NodeAnimationsMap::Builder*
- node_animations_map_builder) const = 0;
+ render_tree::CompositionNode::Builder* border_node_builder) const = 0;
// A transformable element is an element whose layout is governed by the CSS
// box model which is either a block-level or atomic inline-level element.
@@ -564,6 +571,14 @@
const base::optional<LayoutUnit>& possibly_overconstrained_margin_right);
private:
+ struct CachedRenderTreeNodeInfo {
+ explicit CachedRenderTreeNodeInfo(const math::Vector2dF& offset)
+ : offset_(offset) {}
+
+ math::Vector2dF offset_;
+ scoped_refptr<render_tree::Node> node_;
+ };
+
// Updates used values of "border" properties.
void UpdateBorders();
// Updates used values of "padding" properties.
@@ -583,47 +598,40 @@
void RenderAndAnimateBorder(
const base::optional<render_tree::RoundedCorners>& rounded_corners,
render_tree::CompositionNode::Builder* border_node_builder,
- render_tree::animations::NodeAnimationsMap::Builder*
- node_animations_map_builder) const;
+ render_tree::animations::AnimateNode::Builder* animate_node_builder);
void RenderAndAnimateBackgroundColor(
const base::optional<render_tree::RoundedCorners>& rounded_corners,
render_tree::CompositionNode::Builder* border_node_builder,
- render_tree::animations::NodeAnimationsMap::Builder*
- node_animations_map_builder) const;
+ render_tree::animations::AnimateNode::Builder* animate_node_builder);
void RenderAndAnimateBackgroundImage(
const base::optional<render_tree::RoundedCorners>& rounded_corners,
render_tree::CompositionNode::Builder* border_node_builder,
- render_tree::animations::NodeAnimationsMap::Builder*
- node_animations_map_builder) const;
+ render_tree::animations::AnimateNode::Builder* animate_node_builder);
void RenderAndAnimateBoxShadow(
const base::optional<render_tree::RoundedCorners>& rounded_corners,
render_tree::CompositionNode::Builder* border_node_builder,
- render_tree::animations::NodeAnimationsMap::Builder*
- node_animations_map_builder) const;
+ render_tree::animations::AnimateNode::Builder* animate_node_builder);
// If opacity is animated or other than 1, wraps a border node into a filter
// node. Otherwise returns the original border node.
scoped_refptr<render_tree::Node> RenderAndAnimateOpacity(
const scoped_refptr<render_tree::Node>& border_node,
- render_tree::animations::NodeAnimationsMap::Builder*
- node_animations_map_builder,
- float opacity, bool opacity_animated) const;
+ render_tree::animations::AnimateNode::Builder* animate_node_builder,
+ float opacity, bool opacity_animated);
scoped_refptr<render_tree::Node> RenderAndAnimateOverflow(
const base::optional<render_tree::RoundedCorners>& rounded_corners,
const scoped_refptr<render_tree::Node>& border_node,
- render_tree::animations::NodeAnimationsMap::Builder*
- node_animations_map_builder,
- const math::Vector2dF& border_node_offset) const;
+ render_tree::animations::AnimateNode::Builder* animate_node_builder,
+ const math::Vector2dF& border_node_offset);
// If transform is not "none", wraps a border node in a MatrixTransformNode.
// If transform is "none", returns the original border node and leaves
// |border_node_transform| intact.
scoped_refptr<render_tree::Node> RenderAndAnimateTransform(
const scoped_refptr<render_tree::Node>& border_node,
- render_tree::animations::NodeAnimationsMap::Builder*
- node_animations_map_builder,
- const math::Vector2dF& border_node_offset) const;
+ render_tree::animations::AnimateNode::Builder* animate_node_builder,
+ const math::Vector2dF& border_node_offset);
// The css_computed_style_declaration_ member references the
// cssom::CSSComputedStyleDeclaration object owned by the HTML Element from
@@ -681,6 +689,10 @@
// parameters we were passed during in last call to UpdateSizes().
base::optional<LayoutParams> last_update_size_params_;
+ // Render tree node caching is used to prevent the node from needing to be
+ // recalculated during each call to RenderAndAnimateContent.
+ base::optional<CachedRenderTreeNodeInfo> cached_render_tree_node_info_;
+
// For write access to parent/containing_block members.
friend class ContainerBox;
friend class LayoutBoxes;
diff --git a/src/cobalt/layout/box_generator.cc b/src/cobalt/layout/box_generator.cc
index a2affb9..1f2d803 100644
--- a/src/cobalt/layout/box_generator.cc
+++ b/src/cobalt/layout/box_generator.cc
@@ -317,8 +317,8 @@
scoped_refptr<cssom::CSSComputedStyleDeclaration>
css_computed_style_declaration = new cssom::CSSComputedStyleDeclaration();
- css_computed_style_declaration->set_data(
- GetComputedStyleOfAnonymousBox(br_element->computed_style()));
+ css_computed_style_declaration->SetData(GetComputedStyleOfAnonymousBox(
+ br_element->css_computed_style_declaration()));
css_computed_style_declaration->set_animations(br_element->animations());
@@ -802,7 +802,7 @@
new_data->AssignFrom(*style->data());
new_data->SetPropertyValue(cssom::kBackgroundColorProperty, NULL);
new_data->SetPropertyValue(cssom::kBackgroundImageProperty, NULL);
- new_style->set_data(new_data);
+ new_style->SetData(new_data);
return new_style;
}
@@ -880,8 +880,8 @@
void BoxGenerator::Visit(dom::Text* text) {
scoped_refptr<cssom::CSSComputedStyleDeclaration>
css_computed_style_declaration = new cssom::CSSComputedStyleDeclaration();
- css_computed_style_declaration->set_data(GetComputedStyleOfAnonymousBox(
- parent_css_computed_style_declaration_->data()));
+ css_computed_style_declaration->SetData(
+ GetComputedStyleOfAnonymousBox(parent_css_computed_style_declaration_));
// Copy the animations from the parent.
css_computed_style_declaration->set_animations(parent_animations_);
diff --git a/src/cobalt/layout/container_box.cc b/src/cobalt/layout/container_box.cc
index 24f72b1..4ee4b0b 100644
--- a/src/cobalt/layout/container_box.cc
+++ b/src/cobalt/layout/container_box.cc
@@ -93,6 +93,9 @@
split_sibling->GetStackingContext()->are_cross_references_valid_ = false;
}
+ // Invalidate the render tree nodes now that the children have changed.
+ InvalidateRenderTreeNodesOfBoxAndAncestors();
+
return split_sibling_position;
}
@@ -138,6 +141,9 @@
!non_negative_z_index_child_.empty()) {
are_cross_references_valid_ = false;
}
+
+ // Invalidate the render tree nodes now that the children have changed.
+ InvalidateRenderTreeNodesOfBoxAndAncestors();
}
// Returns true if the given style allows a container box to act as a containing
@@ -471,8 +477,6 @@
void ContainerBox::RenderAndAnimateStackingContextChildren(
const ZIndexSortedList& z_index_child_list,
render_tree::CompositionNode::Builder* content_node_builder,
- render_tree::animations::NodeAnimationsMap::Builder*
- node_animations_map_builder,
const Vector2dLayoutUnit& offset_from_parent_node) const {
// Render all children of the passed in list in sorted order.
for (ZIndexSortedList::const_iterator iter = z_index_child_list.begin();
@@ -484,8 +488,7 @@
GetOffsetFromStackingContextToContainingBlock(child_box) +
offset_from_parent_node;
- child_box->RenderAndAnimate(content_node_builder,
- node_animations_map_builder, position_offset);
+ child_box->RenderAndAnimate(content_node_builder, position_offset);
}
}
@@ -552,9 +555,7 @@
}
void ContainerBox::RenderAndAnimateContent(
- render_tree::CompositionNode::Builder* border_node_builder,
- render_tree::animations::NodeAnimationsMap::Builder*
- node_animations_map_builder) const {
+ render_tree::CompositionNode::Builder* border_node_builder) const {
// Ensure that the cross references are up to date.
const_cast<ContainerBox*>(this)->UpdateCrossReferences();
@@ -564,22 +565,19 @@
// z-index values.
// https://www.w3.org/TR/CSS21/visuren.html#z-index
RenderAndAnimateStackingContextChildren(
- negative_z_index_child_, border_node_builder, node_animations_map_builder,
- content_box_offset);
+ negative_z_index_child_, border_node_builder, content_box_offset);
// Render laid out child boxes.
for (Boxes::const_iterator child_box_iterator = child_boxes_.begin();
child_box_iterator != child_boxes_.end(); ++child_box_iterator) {
Box* child_box = *child_box_iterator;
if (!child_box->IsPositioned() && !child_box->IsTransformed()) {
- child_box->RenderAndAnimate(
- border_node_builder, node_animations_map_builder, content_box_offset);
+ child_box->RenderAndAnimate(border_node_builder, content_box_offset);
}
}
// Render all positioned children with non-negative z-index values.
// https://www.w3.org/TR/CSS21/visuren.html#z-index
RenderAndAnimateStackingContextChildren(
- non_negative_z_index_child_, border_node_builder,
- node_animations_map_builder, content_box_offset);
+ non_negative_z_index_child_, border_node_builder, content_box_offset);
}
#ifdef COBALT_BOX_DUMP_ENABLED
diff --git a/src/cobalt/layout/container_box.h b/src/cobalt/layout/container_box.h
index 31aba2b..2a13c91 100644
--- a/src/cobalt/layout/container_box.h
+++ b/src/cobalt/layout/container_box.h
@@ -62,10 +62,8 @@
ContainerBox* AsContainerBox() OVERRIDE;
const ContainerBox* AsContainerBox() const OVERRIDE;
- void RenderAndAnimateContent(
- render_tree::CompositionNode::Builder* border_node_builder,
- render_tree::animations::NodeAnimationsMap::Builder*
- node_animations_map_builder) const OVERRIDE;
+ void RenderAndAnimateContent(render_tree::CompositionNode::Builder*
+ border_node_builder) const OVERRIDE;
#ifdef COBALT_BOX_DUMP_ENABLED
void DumpChildrenWithIndent(std::ostream* stream, int indent) const OVERRIDE;
@@ -167,8 +165,6 @@
void RenderAndAnimateStackingContextChildren(
const ZIndexSortedList& z_index_child_list,
render_tree::CompositionNode::Builder* border_node_builder,
- render_tree::animations::NodeAnimationsMap::Builder*
- node_animations_map_builder,
const Vector2dLayoutUnit& offset_from_parent_node) const;
// A list of our direct children. If a box is one of our child boxes, we
diff --git a/src/cobalt/layout/initial_containing_block.cc b/src/cobalt/layout/initial_containing_block.cc
index 7c22f89..6bf5891 100644
--- a/src/cobalt/layout/initial_containing_block.cc
+++ b/src/cobalt/layout/initial_containing_block.cc
@@ -98,7 +98,7 @@
scoped_refptr<cssom::CSSComputedStyleDeclaration> initial_style_state =
new cssom::CSSComputedStyleDeclaration();
- initial_style_state->set_data(initial_containing_block_style);
+ initial_style_state->SetData(initial_containing_block_style);
initial_style_state->set_animations(new web_animations::AnimationSet());
results.box = make_scoped_refptr(new BlockLevelBlockContainerBox(
diff --git a/src/cobalt/layout/inline_container_box.cc b/src/cobalt/layout/inline_container_box.cc
index 062bc6e..4ce8255 100644
--- a/src/cobalt/layout/inline_container_box.cc
+++ b/src/cobalt/layout/inline_container_box.cc
@@ -222,10 +222,17 @@
return false;
}
-void InlineContainerBox::ResetEllipses() {
+void InlineContainerBox::DoPreEllipsisPlacementProcessing() {
for (Boxes::const_iterator child_box_iterator = child_boxes().begin();
child_box_iterator != child_boxes().end(); ++child_box_iterator) {
- (*child_box_iterator)->ResetEllipses();
+ (*child_box_iterator)->DoPreEllipsisPlacementProcessing();
+ }
+}
+
+void InlineContainerBox::DoPostEllipsisPlacementProcessing() {
+ for (Boxes::const_iterator child_box_iterator = child_boxes().begin();
+ child_box_iterator != child_boxes().end(); ++child_box_iterator) {
+ (*child_box_iterator)->DoPostEllipsisPlacementProcessing();
}
}
diff --git a/src/cobalt/layout/inline_container_box.h b/src/cobalt/layout/inline_container_box.h
index 8c873a0..6444c0e 100644
--- a/src/cobalt/layout/inline_container_box.h
+++ b/src/cobalt/layout/inline_container_box.h
@@ -58,7 +58,8 @@
Box* GetSplitSibling() const OVERRIDE;
bool DoesFulfillEllipsisPlacementRequirement() const OVERRIDE;
- void ResetEllipses() OVERRIDE;
+ void DoPreEllipsisPlacementProcessing() OVERRIDE;
+ void DoPostEllipsisPlacementProcessing() OVERRIDE;
bool TrySplitAtSecondBidiLevelRun() OVERRIDE;
base::optional<int> GetBidiLevel() const OVERRIDE;
diff --git a/src/cobalt/layout/inline_level_replaced_box.cc b/src/cobalt/layout/inline_level_replaced_box.cc
index 8603e7d..9d6072c 100644
--- a/src/cobalt/layout/inline_level_replaced_box.cc
+++ b/src/cobalt/layout/inline_level_replaced_box.cc
@@ -35,7 +35,8 @@
text_position, maybe_intrinsic_width, maybe_intrinsic_height,
maybe_intrinsic_ratio, used_style_provider,
layout_stat_tracker),
- is_hidden_by_ellipsis_(false) {}
+ is_hidden_by_ellipsis_(false),
+ was_hidden_by_ellipsis_(false) {}
Box::Level InlineLevelReplacedBox::GetLevel() const { return kInlineLevel; }
@@ -46,7 +47,16 @@
return true;
}
-void InlineLevelReplacedBox::ResetEllipses() { is_hidden_by_ellipsis_ = false; }
+void InlineLevelReplacedBox::DoPreEllipsisPlacementProcessing() {
+ was_hidden_by_ellipsis_ = is_hidden_by_ellipsis_;
+ is_hidden_by_ellipsis_ = false;
+}
+
+void InlineLevelReplacedBox::DoPostEllipsisPlacementProcessing() {
+ if (was_hidden_by_ellipsis_ != is_hidden_by_ellipsis_) {
+ InvalidateRenderTreeNodesOfBoxAndAncestors();
+ }
+}
bool InlineLevelReplacedBox::IsHiddenByEllipsis() const {
return is_hidden_by_ellipsis_;
diff --git a/src/cobalt/layout/inline_level_replaced_box.h b/src/cobalt/layout/inline_level_replaced_box.h
index a53c1f6..b0f1a25 100644
--- a/src/cobalt/layout/inline_level_replaced_box.h
+++ b/src/cobalt/layout/inline_level_replaced_box.h
@@ -48,7 +48,8 @@
Level GetLevel() const OVERRIDE;
bool DoesFulfillEllipsisPlacementRequirement() const OVERRIDE;
- void ResetEllipses() OVERRIDE;
+ void DoPreEllipsisPlacementProcessing() OVERRIDE;
+ void DoPostEllipsisPlacementProcessing() OVERRIDE;
bool IsHiddenByEllipsis() const OVERRIDE;
protected:
@@ -76,6 +77,11 @@
// the applicable edge(s) of the line as necessary to fit the ellipsis."
// https://www.w3.org/TR/css3-ui/#propdef-text-overflow
bool is_hidden_by_ellipsis_;
+ // Tracking of the previous value of |is_hidden_by_ellipsis_|, which allows
+ // for determination of whether or not the value changed during ellipsis
+ // placement. When this occurs, the cached render tree nodes of this box and
+ // its ancestors are invalidated.
+ bool was_hidden_by_ellipsis_;
};
} // namespace layout
diff --git a/src/cobalt/layout/layout.cc b/src/cobalt/layout/layout.cc
index 9acfffb..d517a4f 100644
--- a/src/cobalt/layout/layout.cc
+++ b/src/cobalt/layout/layout.cc
@@ -28,7 +28,7 @@
#include "cobalt/layout/box_generator.h"
#include "cobalt/layout/initial_containing_block.h"
#include "cobalt/layout/used_style.h"
-#include "cobalt/render_tree/animations/node_animations_map.h"
+#include "cobalt/render_tree/animations/animate_node.h"
namespace cobalt {
namespace layout {
@@ -73,8 +73,8 @@
// Create initial containing block.
InitialContainingBlockCreationResults
initial_containing_block_creation_results = CreateInitialContainingBlock(
- document->initial_computed_style(), document, used_style_provider,
- layout_stat_tracker);
+ document->initial_computed_style_data(), document,
+ used_style_provider, layout_stat_tracker);
*initial_containing_block = initial_containing_block_creation_results.box;
// Generate boxes.
@@ -128,7 +128,7 @@
}
}
-RenderTreeWithAnimations Layout(
+scoped_refptr<render_tree::Node> Layout(
const icu::Locale& locale, const scoped_refptr<dom::Document>& document,
UsedStyleProvider* used_style_provider,
LayoutStatTracker* layout_stat_tracker,
@@ -141,8 +141,6 @@
line_break_iterator, character_break_iterator, initial_containing_block);
// Add to render tree.
- render_tree::animations::NodeAnimationsMap::Builder
- node_animations_map_builder;
render_tree::CompositionNode::Builder render_tree_root_builder;
{
TRACE_EVENT0("cobalt::layout", kBenchmarkStatRenderAndAnimate);
@@ -151,14 +149,18 @@
base::StopWatch::kAutoStartOn, layout_stat_tracker);
(*initial_containing_block)
- ->RenderAndAnimate(&render_tree_root_builder,
- &node_animations_map_builder, math::Vector2dF(0, 0));
+ ->RenderAndAnimate(&render_tree_root_builder, math::Vector2dF(0, 0));
}
- return RenderTreeWithAnimations(
- new render_tree::CompositionNode(render_tree_root_builder.Pass()),
- new render_tree::animations::NodeAnimationsMap(
- node_animations_map_builder.Pass()));
+ render_tree::CompositionNode* static_root_node =
+ new render_tree::CompositionNode(render_tree_root_builder.Pass());
+
+ // Make it easy to animate the entire tree by placing an AnimateNode at the
+ // root to merge any sub-AnimateNodes.
+ render_tree::animations::AnimateNode* animate_node =
+ new render_tree::animations::AnimateNode(static_root_node);
+
+ return animate_node;
}
} // namespace layout
diff --git a/src/cobalt/layout/layout.h b/src/cobalt/layout/layout.h
index 9b8bf8e..d9cdf7a 100644
--- a/src/cobalt/layout/layout.h
+++ b/src/cobalt/layout/layout.h
@@ -21,7 +21,7 @@
#include "cobalt/layout/block_formatting_block_container_box.h"
#include "cobalt/loader/image/image_cache.h"
#include "cobalt/math/size_f.h"
-#include "cobalt/render_tree/animations/node_animations_map.h"
+#include "cobalt/render_tree/animations/animate_node.h"
#include "cobalt/render_tree/node.h"
#include "cobalt/render_tree/resource_provider.h"
#include "third_party/icu/public/common/unicode/brkiter.h"
@@ -40,17 +40,6 @@
// (https://www.w3.org/TR/CSS2/visuren.html) as recommended by a newer draft
// (http://dev.w3.org/csswg/css-box/) which is undergoing active changes.
-struct RenderTreeWithAnimations {
- RenderTreeWithAnimations(
- const scoped_refptr<render_tree::Node>& render_tree,
- const scoped_refptr<render_tree::animations::NodeAnimationsMap>&
- animations)
- : render_tree(render_tree), animations(animations) {}
-
- scoped_refptr<render_tree::Node> render_tree;
- scoped_refptr<render_tree::animations::NodeAnimationsMap> animations;
-};
-
// Update the computed styles, then generate and layout the box tree.
void UpdateComputedStylesAndLayoutBoxTree(
const icu::Locale& locale, const scoped_refptr<dom::Document>& document,
@@ -63,7 +52,7 @@
// Main entry point to the layout engine.
// Produces the render tree (along with corresponding animations) which is a
// result of recursive layout of the given HTML element.
-RenderTreeWithAnimations Layout(
+scoped_refptr<render_tree::Node> Layout(
const icu::Locale& locale, const scoped_refptr<dom::Document>& document,
UsedStyleProvider* used_style_provider,
LayoutStatTracker* layout_stat_tracker,
diff --git a/src/cobalt/layout/layout_boxes.cc b/src/cobalt/layout/layout_boxes.cc
index 2c65d99..8a95115 100644
--- a/src/cobalt/layout/layout_boxes.cc
+++ b/src/cobalt/layout/layout_boxes.cc
@@ -159,6 +159,17 @@
}
}
+void LayoutBoxes::InvalidateRenderTreeNodes() {
+ for (Boxes::const_iterator box_iterator = boxes_.begin();
+ box_iterator != boxes_.end(); ++box_iterator) {
+ Box* box = *box_iterator;
+ do {
+ box->InvalidateRenderTreeNodesOfBoxAndAncestors();
+ box = box->GetSplitSibling();
+ } while (box != NULL);
+ }
+}
+
math::RectF LayoutBoxes::GetBoundingBorderRectangle() const {
// In the CSSOM View extensions to the HTMLElement interface, at
// https://www.w3.org/TR/2013/WD-cssom-view-20131217/#extensions-to-the-htmlelement-interface,
diff --git a/src/cobalt/layout/layout_boxes.h b/src/cobalt/layout/layout_boxes.h
index 28708a8..055d1e0 100644
--- a/src/cobalt/layout/layout_boxes.h
+++ b/src/cobalt/layout/layout_boxes.h
@@ -58,6 +58,7 @@
void InvalidateSizes() OVERRIDE;
void InvalidateCrossReferences() OVERRIDE;
+ void InvalidateRenderTreeNodes() OVERRIDE;
// Other
//
diff --git a/src/cobalt/layout/layout_manager.cc b/src/cobalt/layout/layout_manager.cc
index b92c47b..c0fb5c6 100644
--- a/src/cobalt/layout/layout_manager.cc
+++ b/src/cobalt/layout/layout_manager.cc
@@ -239,7 +239,7 @@
TRACE_EVENT_BEGIN0("cobalt::layout", kBenchmarkStatLayout);
}
- RenderTreeWithAnimations render_tree_with_animations = layout::Layout(
+ scoped_refptr<render_tree::Node> render_tree_root = layout::Layout(
locale_, window_->document(), used_style_provider_.get(),
layout_stat_tracker_, line_break_iterator_.get(),
character_break_iterator_.get(), &initial_containing_block_);
@@ -251,11 +251,9 @@
}
#endif // ENABLE_TEST_RUNNER
if (run_on_render_tree_produced_callback) {
- on_render_tree_produced_callback_.Run(
- LayoutResults(render_tree_with_animations.render_tree,
- render_tree_with_animations.animations,
- base::TimeDelta::FromMillisecondsD(
- *document->timeline()->current_time())));
+ on_render_tree_produced_callback_.Run(LayoutResults(
+ render_tree_root, base::TimeDelta::FromMillisecondsD(
+ *document->timeline()->current_time())));
}
layout_dirty_ = false;
diff --git a/src/cobalt/layout/layout_manager.h b/src/cobalt/layout/layout_manager.h
index 4a9b405..39e4eb7 100644
--- a/src/cobalt/layout/layout_manager.h
+++ b/src/cobalt/layout/layout_manager.h
@@ -25,7 +25,6 @@
#include "cobalt/dom/window.h"
#include "cobalt/layout/layout_stat_tracker.h"
#include "cobalt/loader/image/image_cache.h"
-#include "cobalt/render_tree/animations/node_animations_map.h"
#include "cobalt/render_tree/node.h"
#include "cobalt/render_tree/resource_provider.h"
@@ -37,19 +36,15 @@
public:
struct LayoutResults {
LayoutResults(const scoped_refptr<render_tree::Node>& render_tree,
- const scoped_refptr<
- render_tree::animations::NodeAnimationsMap>& animations,
const base::TimeDelta& layout_time)
: render_tree(render_tree),
- animations(animations),
layout_time(layout_time) {}
// The render tree produced by a layout.
scoped_refptr<render_tree::Node> render_tree;
- // Animations that are to be applied to the layout's render tree.
- scoped_refptr<render_tree::animations::NodeAnimationsMap> animations;
+
// The time that the render tree was created, which will be used as a
- // reference point for updating the animations specified above.
+ // reference point for updating the animations in the above render tree.
base::TimeDelta layout_time;
};
diff --git a/src/cobalt/layout/render_tree_animations.h b/src/cobalt/layout/render_tree_animations.h
index 07121eb..0c8a862 100644
--- a/src/cobalt/layout/render_tree_animations.h
+++ b/src/cobalt/layout/render_tree_animations.h
@@ -33,6 +33,15 @@
// a convenience function that can be used by code that creates render tree
// nodes (e.g. layout box tree processing).
+// This callback function defines a function that is expected to populate a
+// given CSS style object for a render tree node type.
+class PopulateBaseStyleForRenderTreeNode {
+ public:
+ typedef base::Callback<void(
+ const scoped_refptr<const cssom::CSSComputedStyleData>&,
+ const scoped_refptr<cssom::CSSComputedStyleData>&)> Function;
+};
+
// This callback function defines a function that is expected to apply a given
// CSS style to a render tree node builder object. A function meeting this
// specification can be passed into AddAnimations() in order to
@@ -47,16 +56,16 @@
typename T::Builder*)> Function;
};
-// Helper function that applies a animation set to a base style to produce
+// Helper function that applies an animation set to a base style to produce
// an animated style that is then passed into the provided
// ApplyStyleToRenderTreeNode<T>::Function callback function.
template <typename T>
-void AnimateNode(const typename ApplyStyleToRenderTreeNode<T>::Function&
- apply_style_function,
- const web_animations::BakedAnimationSet& animations,
- const scoped_refptr<cssom::CSSComputedStyleData>& base_style,
- typename T::Builder* node_builder,
- base::TimeDelta time_elapsed) {
+void ApplyAnimation(
+ const typename ApplyStyleToRenderTreeNode<T>::Function&
+ apply_style_function,
+ const web_animations::BakedAnimationSet& animations,
+ const scoped_refptr<cssom::CSSComputedStyleData>& base_style,
+ typename T::Builder* node_builder, base::TimeDelta time_elapsed) {
scoped_refptr<cssom::CSSComputedStyleData> animated_style =
new cssom::CSSComputedStyleData();
animated_style->AssignFrom(*base_style);
@@ -65,26 +74,30 @@
}
// If animations exist, this function will add an animation which represents
-// the animations to the passed in NodeAnimationsMap. The animation will
+// the animations to the passed in ApplyAnimation. The animation will
// target the passed in render tree node.
template <typename T>
void AddAnimations(
+ const typename PopulateBaseStyleForRenderTreeNode::Function&
+ populate_base_style_function,
const typename ApplyStyleToRenderTreeNode<T>::Function&
apply_style_function,
const cssom::CSSComputedStyleDeclaration& css_computed_style_declaration,
const scoped_refptr<T>& target_node,
- render_tree::animations::NodeAnimationsMap::Builder*
- node_animation_map_builder) {
+ render_tree::animations::AnimateNode::Builder* node_animation_map_builder) {
DCHECK(!css_computed_style_declaration.animations()->IsEmpty());
- scoped_refptr<cssom::CSSComputedStyleData> base_style_copy =
+
+ // Populate the base style.
+ scoped_refptr<cssom::CSSComputedStyleData> base_style =
new cssom::CSSComputedStyleData();
- base_style_copy->AssignFrom(*css_computed_style_declaration.data());
+ populate_base_style_function.Run(css_computed_style_declaration.data(),
+ base_style);
node_animation_map_builder->Add(
- target_node, base::Bind(&AnimateNode<T>, apply_style_function,
+ target_node, base::Bind(&ApplyAnimation<T>, apply_style_function,
web_animations::BakedAnimationSet(
*css_computed_style_declaration.animations()),
- base_style_copy));
+ base_style));
}
} // namespace layout
diff --git a/src/cobalt/layout/replaced_box.cc b/src/cobalt/layout/replaced_box.cc
index 62b771f..15f0d6a 100644
--- a/src/cobalt/layout/replaced_box.cc
+++ b/src/cobalt/layout/replaced_box.cc
@@ -46,7 +46,7 @@
namespace cobalt {
namespace layout {
-using render_tree::animations::NodeAnimationsMap;
+using render_tree::animations::AnimateNode;
using render_tree::CompositionNode;
using render_tree::ImageNode;
using render_tree::PunchThroughVideoNode;
@@ -239,8 +239,7 @@
} // namespace
void ReplacedBox::RenderAndAnimateContent(
- CompositionNode::Builder* border_node_builder,
- NodeAnimationsMap::Builder* node_animations_map_builder) const {
+ CompositionNode::Builder* border_node_builder) const {
if (computed_style()->visibility() != cssom::KeywordValue::GetVisible()) {
return;
}
@@ -257,11 +256,13 @@
scoped_refptr<CompositionNode> composition_node =
new CompositionNode(composition_node_builder);
- node_animations_map_builder->Add(
+ AnimateNode::Builder animate_node_builder;
+ animate_node_builder.Add(
composition_node,
base::Bind(AnimateCB, replace_image_cb_, content_box_size()));
- border_node_builder->AddChild(composition_node);
+ border_node_builder->AddChild(
+ new AnimateNode(animate_node_builder, composition_node));
}
void ReplacedBox::UpdateContentSizeAndMargins(
diff --git a/src/cobalt/layout/replaced_box.h b/src/cobalt/layout/replaced_box.h
index f503db3..259b2d0 100644
--- a/src/cobalt/layout/replaced_box.h
+++ b/src/cobalt/layout/replaced_box.h
@@ -76,10 +76,8 @@
// From |Box|.
void UpdateContentSizeAndMargins(const LayoutParams& layout_params) OVERRIDE;
- void RenderAndAnimateContent(
- render_tree::CompositionNode::Builder* border_node_builder,
- render_tree::animations::NodeAnimationsMap::Builder*
- node_animations_map_builder) const OVERRIDE;
+ void RenderAndAnimateContent(render_tree::CompositionNode::Builder*
+ border_node_builder) const OVERRIDE;
bool IsTransformable() const OVERRIDE { return true; }
diff --git a/src/cobalt/layout/text_box.cc b/src/cobalt/layout/text_box.cc
index 84e5823..1b4e96e 100644
--- a/src/cobalt/layout/text_box.cc
+++ b/src/cobalt/layout/text_box.cc
@@ -46,6 +46,7 @@
text_start_position_(text_start_position),
text_end_position_(text_end_position),
truncated_text_end_position_(text_end_position),
+ previous_truncated_text_end_position_(text_end_position),
truncated_text_offset_from_left_(0),
used_font_(used_style_provider->GetUsedFontList(
css_computed_style_declaration->data()->font_family(),
@@ -225,10 +226,17 @@
return GetNonCollapsedTextStartPosition() < GetNonCollapsedTextEndPosition();
}
-void TextBox::ResetEllipses() {
+void TextBox::DoPreEllipsisPlacementProcessing() {
+ previous_truncated_text_end_position_ = truncated_text_end_position_;
truncated_text_end_position_ = text_end_position_;
}
+void TextBox::DoPostEllipsisPlacementProcessing() {
+ if (previous_truncated_text_end_position_ != truncated_text_end_position_) {
+ InvalidateRenderTreeNodesOfBoxAndAncestors();
+ }
+}
+
void TextBox::SplitBidiLevelRuns() {}
bool TextBox::TrySplitAtSecondBidiLevelRun() {
@@ -299,6 +307,14 @@
}
namespace {
+void PopulateBaseStyleForTextNode(
+ const scoped_refptr<const cssom::CSSComputedStyleData>& source_style,
+ const scoped_refptr<cssom::CSSComputedStyleData>& destination_style) {
+ // NOTE: Properties set by PopulateBaseStyleForTextNode() should match the
+ // properties used by SetupTextNodeFromStyle().
+ destination_style->set_color(source_style->color());
+}
+
void SetupTextNodeFromStyle(
const scoped_refptr<const cssom::CSSComputedStyleData>& style,
render_tree::TextNode::Builder* text_node_builder) {
@@ -340,11 +356,7 @@
} // namespace
void TextBox::RenderAndAnimateContent(
- render_tree::CompositionNode::Builder* border_node_builder,
- render_tree::animations::NodeAnimationsMap::Builder*
- node_animations_map_builder) const {
- UNREFERENCED_PARAMETER(node_animations_map_builder);
-
+ render_tree::CompositionNode::Builder* border_node_builder) const {
if (computed_style()->visibility() != cssom::KeywordValue::GetVisible()) {
return;
}
@@ -376,23 +388,15 @@
text_shadow != cssom::KeywordValue::GetNone()) {
int32 text_start_position = GetNonCollapsedTextStartPosition();
int32 text_length = GetVisibleTextLength();
- // Generate the glyph buffer if it does not already exist or the position
- // it covers has changed. Otherwise, just use the cached glyph buffer.
- if (!cached_glyph_buffer_info_.glyph_buffer ||
- text_start_position != cached_glyph_buffer_info_.start_position ||
- text_length != cached_glyph_buffer_info_.length) {
- cached_glyph_buffer_info_.start_position = text_start_position;
- cached_glyph_buffer_info_.length = text_length;
- cached_glyph_buffer_info_.glyph_buffer = used_font_->CreateGlyphBuffer(
- paragraph_->GetTextBuffer() +
- cached_glyph_buffer_info_.start_position,
- cached_glyph_buffer_info_.length,
- paragraph_->IsRTL(text_start_position));
- }
+
+ scoped_refptr<render_tree::GlyphBuffer> glyph_buffer =
+ used_font_->CreateGlyphBuffer(
+ paragraph_->GetTextBuffer() + text_start_position, text_length,
+ paragraph_->IsRTL(text_start_position));
render_tree::TextNode::Builder text_node_builder(
math::Vector2dF(truncated_text_offset_from_left_, ascent_),
- cached_glyph_buffer_info_.glyph_buffer, used_color);
+ glyph_buffer, used_color);
if (text_shadow != cssom::KeywordValue::GetNone()) {
cssom::PropertyListValue* shadow_list =
@@ -407,13 +411,20 @@
// The render tree API considers text coordinates to be a position
// of a baseline, offset the text node accordingly.
- border_node_builder->AddChild(text_node);
+ scoped_refptr<render_tree::Node> node_to_add;
if (is_color_animated) {
+ render_tree::animations::AnimateNode::Builder animate_node_builder;
AddAnimations<render_tree::TextNode>(
+ base::Bind(&PopulateBaseStyleForTextNode),
base::Bind(&SetupTextNodeFromStyle),
*css_computed_style_declaration(), text_node,
- node_animations_map_builder);
+ &animate_node_builder);
+ node_to_add = new render_tree::animations::AnimateNode(
+ animate_node_builder, text_node);
+ } else {
+ node_to_add = text_node;
}
+ border_node_builder->AddChild(node_to_add);
}
}
}
diff --git a/src/cobalt/layout/text_box.h b/src/cobalt/layout/text_box.h
index 792e5a7..dc55439 100644
--- a/src/cobalt/layout/text_box.h
+++ b/src/cobalt/layout/text_box.h
@@ -57,7 +57,8 @@
Box* GetSplitSibling() const OVERRIDE;
bool DoesFulfillEllipsisPlacementRequirement() const OVERRIDE;
- void ResetEllipses() OVERRIDE;
+ void DoPreEllipsisPlacementProcessing() OVERRIDE;
+ void DoPostEllipsisPlacementProcessing() OVERRIDE;
void SplitBidiLevelRuns() OVERRIDE;
bool TrySplitAtSecondBidiLevelRun() OVERRIDE;
@@ -82,10 +83,8 @@
protected:
// From |Box|.
- void RenderAndAnimateContent(
- render_tree::CompositionNode::Builder* border_node_builder,
- render_tree::animations::NodeAnimationsMap::Builder*
- node_animations_map_builder) const OVERRIDE;
+ void RenderAndAnimateContent(render_tree::CompositionNode::Builder*
+ border_node_builder) const OVERRIDE;
bool IsTransformable() const OVERRIDE;
#ifdef COBALT_BOX_DUMP_ENABLED
@@ -95,14 +94,6 @@
#endif // COBALT_BOX_DUMP_ENABLED
private:
- struct CachedGlyphBufferInfo {
- CachedGlyphBufferInfo() : start_position(-1), length(0) {}
-
- scoped_refptr<render_tree::GlyphBuffer> glyph_buffer;
- int32 start_position;
- int32 length;
- };
-
// From |Box|.
void DoPlaceEllipsisOrProcessPlacedEllipsis(
BaseDirection base_direction, LayoutUnit desired_offset,
@@ -162,6 +153,11 @@
// the applicable edge(s) of the line as necessary to fit the ellipsis."
// https://www.w3.org/TR/css3-ui/#propdef-text-overflow
int32 truncated_text_end_position_;
+ // Tracking of the previous value of |truncated_text_end_position_|, which
+ // allows for determination of whether or not the value changed during
+ // ellipsis placement. When this occurs, the cached render tree nodes of this
+ // box and its ancestors are invalidated.
+ int32 previous_truncated_text_end_position_;
// The horizontal offset to apply to rendered text as a result of an ellipsis
// truncating the text. This value can be non-zero when the text box is in a
// line with a right-to-left base direction. In this case, when an ellipsis is
@@ -197,11 +193,6 @@
// The width of the portion of the text that is unaffected by whitespace
// collapsing.
base::optional<LayoutUnit> non_collapsible_text_width_;
-
- // Glyph buffer caching is used to prevent it from needing to be recalculated
- // during each call to RenderAndAnimateContent. It is mutable as a result of
- // RenderAndAnimateContent being const.
- mutable CachedGlyphBufferInfo cached_glyph_buffer_info_;
};
} // namespace layout
diff --git a/src/cobalt/layout_tests/layout_benchmarks.cc b/src/cobalt/layout_tests/layout_benchmarks.cc
index 99e088d..164741c 100644
--- a/src/cobalt/layout_tests/layout_benchmarks.cc
+++ b/src/cobalt/layout_tests/layout_benchmarks.cc
@@ -62,9 +62,8 @@
samples_to_gather_ = samples_to_gather;
done_gathering_samples_.Reset();
- renderer::Submission submission_with_callback(
- layout_results.render_tree, layout_results.animations,
- layout_results.layout_time);
+ renderer::Submission submission_with_callback(layout_results.render_tree,
+ layout_results.layout_time);
submission_with_callback.on_rasterized_callback = base::Bind(
&RendererBenchmarkRunner::OnSubmitComplete, base::Unretained(this));
@@ -156,7 +155,7 @@
layout_samples_[layout::kBenchmarkStatUpdateCrossReferences];
layout_samples_[layout::kBenchmarkStatUpdateUsedSizes];
layout_samples_[layout::kBenchmarkStatRenderAndAnimate];
- renderer_samples_["NodeAnimationsMap::Apply()"];
+ renderer_samples_["AnimateNode::Apply()"];
renderer_samples_["VisitRenderTree"];
renderer_samples_["Skia Flush"];
}
diff --git a/src/cobalt/layout_tests/layout_snapshot.cc b/src/cobalt/layout_tests/layout_snapshot.cc
index b07abfc..97b7689 100644
--- a/src/cobalt/layout_tests/layout_snapshot.cc
+++ b/src/cobalt/layout_tests/layout_snapshot.cc
@@ -41,8 +41,7 @@
base::optional<browser::WebModule::LayoutResults>* out_results,
base::RunLoop* run_loop, MessageLoop* message_loop,
const browser::WebModule::LayoutResults& results) {
- out_results->emplace(results.render_tree, results.animations,
- results.layout_time);
+ out_results->emplace(results.render_tree, results.layout_time);
message_loop->PostTask(FROM_HERE, base::Bind(Quit, run_loop));
}
diff --git a/src/cobalt/layout_tests/layout_tests.cc b/src/cobalt/layout_tests/layout_tests.cc
index 5a822d1..9ceb258 100644
--- a/src/cobalt/layout_tests/layout_tests.cc
+++ b/src/cobalt/layout_tests/layout_tests.cc
@@ -24,6 +24,7 @@
#include "cobalt/layout_tests/layout_snapshot.h"
#include "cobalt/layout_tests/test_parser.h"
#include "cobalt/math/size.h"
+#include "cobalt/render_tree/animations/animate_node.h"
#include "cobalt/renderer/render_tree_pixel_tester.h"
#include "googleurl/src/gurl.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -88,8 +89,13 @@
browser::WebModule::LayoutResults layout_results = SnapshotURL(
GetParam().url, viewport_size, pixel_tester.GetResourceProvider());
- bool results = pixel_tester.TestTree(layout_results.render_tree,
- GetParam().base_file_path);
+ render_tree::animations::AnimateNode* animated_node =
+ base::polymorphic_downcast<render_tree::animations::AnimateNode*>(
+ layout_results.render_tree.get());
+
+ bool results =
+ pixel_tester.TestTree(animated_node->Apply(layout_results.layout_time),
+ GetParam().base_file_path);
EXPECT_TRUE(results);
if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kRebaseline) ||
diff --git a/src/cobalt/layout_tests/web_platform_tests.cc b/src/cobalt/layout_tests/web_platform_tests.cc
index 42dbc90..0c28e1a 100644
--- a/src/cobalt/layout_tests/web_platform_tests.cc
+++ b/src/cobalt/layout_tests/web_platform_tests.cc
@@ -123,8 +123,7 @@
base::optional<browser::WebModule::LayoutResults>* out_results,
base::RunLoop* run_loop, MessageLoop* message_loop,
const browser::WebModule::LayoutResults& results) {
- out_results->emplace(results.render_tree, results.animations,
- results.layout_time);
+ out_results->emplace(results.render_tree, results.layout_time);
message_loop->PostTask(FROM_HERE, base::Bind(Quit, run_loop));
}
diff --git a/src/cobalt/media/sandbox/media_sandbox.cc b/src/cobalt/media/sandbox/media_sandbox.cc
index e3859b0..4f3a1a3 100644
--- a/src/cobalt/media/sandbox/media_sandbox.cc
+++ b/src/cobalt/media/sandbox/media_sandbox.cc
@@ -24,7 +24,7 @@
#include "cobalt/math/size.h"
#include "cobalt/math/size_f.h"
#include "cobalt/network/network_module.h"
-#include "cobalt/render_tree/animations/node_animations_map.h"
+#include "cobalt/render_tree/animations/animate_node.h"
#include "cobalt/render_tree/image_node.h"
#include "cobalt/render_tree/resource_provider.h"
#include "cobalt/renderer/pipeline.h"
@@ -85,7 +85,7 @@
renderer_module_.reset(
new renderer::RendererModule(system_window_.get(), renderer_options));
MediaModule::Options media_module_options;
-#if defined(ENABLE_COMMAND_LINE_SWITCHES)
+#if defined(ENABLE_DEBUG_COMMAND_LINE_SWITCHES)
CommandLine* command_line = CommandLine::ForCurrentProcess();
// Use string literals directly to avoid dependency on browser::switches.
if (command_line->HasSwitch("audio_decoder_stub")) {
@@ -97,7 +97,7 @@
if (command_line->HasSwitch("video_decoder_stub")) {
media_module_options.use_video_decoder_stub = true;
}
-#endif // defined(ENABLE_COMMAND_LINE_SWITCHES)
+#endif // defined(ENABLE_DEBUG_COMMAND_LINE_SWITCHES)
media_module_ =
MediaModule::Create(renderer_module_->render_target()->GetSize(),
@@ -124,16 +124,15 @@
void MediaSandbox::Impl::SetupAndSubmitScene() {
scoped_refptr<render_tree::ImageNode> image_node =
new render_tree::ImageNode(NULL);
- render_tree::animations::NodeAnimationsMap::Builder
- node_animations_map_builder;
+ render_tree::animations::AnimateNode::Builder animate_node_builder;
- node_animations_map_builder.Add(
+ animate_node_builder.Add(
image_node, base::Bind(&Impl::AnimateCB, base::Unretained(this)));
- renderer_module_->pipeline()->Submit(renderer::Submission(
- image_node, new render_tree::animations::NodeAnimationsMap(
- node_animations_map_builder.Pass()),
- base::TimeDelta()));
+ renderer_module_->pipeline()->Submit(
+ renderer::Submission(new render_tree::animations::AnimateNode(
+ animate_node_builder, image_node),
+ base::TimeDelta()));
}
MediaSandbox::MediaSandbox(int argc, char** argv,
diff --git a/src/cobalt/media/sandbox/raw_video_decoder_fuzzer.cc b/src/cobalt/media/sandbox/raw_video_decoder_fuzzer.cc
index b5ab128..724287e 100644
--- a/src/cobalt/media/sandbox/raw_video_decoder_fuzzer.cc
+++ b/src/cobalt/media/sandbox/raw_video_decoder_fuzzer.cc
@@ -192,9 +192,11 @@
scoped_ptr<ShellRawVideoDecoder> decoder =
media_sandbox_->GetMediaModule()->GetRawVideoDecoderFactory()->Create(
demuxer->config(), NULL, false);
- DCHECK(decoder);
- VideoDecoderFuzzer decoder_fuzzer(fuzzing_content, demuxer, decoder.get());
- decoder_fuzzer.Fuzz();
+ if (decoder) {
+ VideoDecoderFuzzer decoder_fuzzer(fuzzing_content, demuxer,
+ decoder.get());
+ decoder_fuzzer.Fuzz();
+ }
}
private:
diff --git a/src/cobalt/media/shell_media_platform_starboard.cc b/src/cobalt/media/shell_media_platform_starboard.cc
index 6278203..096b670 100644
--- a/src/cobalt/media/shell_media_platform_starboard.cc
+++ b/src/cobalt/media/shell_media_platform_starboard.cc
@@ -57,7 +57,8 @@
kGPUMemoryBufferBudget);
gpu_memory_pool_.reset(new nb::MemoryPool(
gpu_memory_buffer_space_->GetMemory(),
- gpu_memory_buffer_space_->GetSizeInBytes(), true /* thread_safe */));
+ gpu_memory_buffer_space_->GetSizeInBytes(), true, /* thread_safe */
+ true /* verify_full_capacity */));
}
DCHECK_LE(0, kMainMemoryBufferBudget > 0);
@@ -66,7 +67,8 @@
DCHECK(main_memory_buffer_space_);
main_memory_pool_.reset(new nb::MemoryPool(main_memory_buffer_space_.get(),
kMainMemoryBufferBudget,
- true /* thread_safe */));
+ true, /* thread_safe */
+ true /* verify_full_capacity */));
ShellBufferFactory::Initialize();
ShellAudioStreamer::Initialize();
diff --git a/src/cobalt/media/shell_video_data_allocator_common.cc b/src/cobalt/media/shell_video_data_allocator_common.cc
index be0107b..de8af74 100644
--- a/src/cobalt/media/shell_video_data_allocator_common.cc
+++ b/src/cobalt/media/shell_video_data_allocator_common.cc
@@ -89,29 +89,30 @@
// TODO: Ensure it work with visible_rect with non-zero left and
// top. Note that simply add offset to the image buffer may cause alignment
// issues.
- gfx::Size visible_size(param.visible_rect().size());
+ gfx::Size plane_size(param.visible_rect().size());
// Create image data descriptor for the frame in I420.
MultiPlaneImageDataDescriptor descriptor(
kMultiPlaneImageFormatYUV3PlaneBT709);
descriptor.AddPlane(
param.y_data() - frame_buffer->data(),
- ImageDataDescriptor(visible_size, kPixelFormatY8,
+ ImageDataDescriptor(plane_size, kPixelFormatY8,
kAlphaFormatUnpremultiplied, param.y_pitch()));
- visible_size.SetSize(visible_size.width() / 2, visible_size.height() / 2);
+ plane_size.SetSize(plane_size.width() / 2, plane_size.height() / 2);
descriptor.AddPlane(
param.u_data() - frame_buffer->data(),
- ImageDataDescriptor(visible_size, kPixelFormatU8,
+ ImageDataDescriptor(plane_size, kPixelFormatU8,
kAlphaFormatUnpremultiplied, param.uv_pitch()));
descriptor.AddPlane(
param.v_data() - frame_buffer->data(),
- ImageDataDescriptor(visible_size, kPixelFormatV8,
+ ImageDataDescriptor(plane_size, kPixelFormatV8,
kAlphaFormatUnpremultiplied, param.uv_pitch()));
scoped_refptr<Image> image =
resource_provider_->CreateMultiPlaneImageFromRawMemory(
frame_buffer_common->DetachRawImageMemory(), descriptor);
+ gfx::Size visible_size(param.visible_rect().size());
// The reference of the image is held by the closure that binds ReleaseImage,
// so it won't be freed before the ReleaseImage is called.
scoped_refptr<VideoFrame> video_frame = VideoFrame::WrapNativeTexture(
@@ -130,7 +131,7 @@
// TODO: Ensure it work with visible_rect with non-zero left and
// top. Note that simply add offset to the image buffer may cause alignment
// issues.
- gfx::Size visible_size(param.visible_rect().size());
+ gfx::Size plane_size(param.visible_rect().size());
intptr_t offset = 0;
int pitch_in_bytes = param.y_pitch();
@@ -141,12 +142,12 @@
MultiPlaneImageDataDescriptor descriptor(
kMultiPlaneImageFormatYUV2PlaneBT709);
descriptor.AddPlane(
- offset, ImageDataDescriptor(visible_size, kPixelFormatY8,
+ offset, ImageDataDescriptor(plane_size, kPixelFormatY8,
kAlphaFormatPremultiplied, pitch_in_bytes));
offset += pitch_in_bytes * param.decoded_height();
- visible_size.SetSize(visible_size.width() / 2, visible_size.height() / 2);
+ plane_size.SetSize(plane_size.width() / 2, plane_size.height() / 2);
descriptor.AddPlane(
- offset, ImageDataDescriptor(visible_size, kPixelFormatUV8,
+ offset, ImageDataDescriptor(plane_size, kPixelFormatUV8,
kAlphaFormatPremultiplied, pitch_in_bytes));
offset += pitch_in_bytes * param.decoded_height() / 2;
DCHECK_EQ(offset, pitch_in_bytes * param.decoded_height() * 3 / 2);
@@ -155,6 +156,7 @@
resource_provider_->CreateMultiPlaneImageFromRawMemory(
frame_buffer_common->DetachRawImageMemory(), descriptor);
+ gfx::Size visible_size(param.visible_rect().size());
// The reference of the image is held by the closure that binds ReleaseImage,
// so it won't be freed before the ReleaseImage is called.
scoped_refptr<VideoFrame> video_frame = VideoFrame::WrapNativeTexture(
diff --git a/src/cobalt/media/shell_video_data_allocator_common.h b/src/cobalt/media/shell_video_data_allocator_common.h
index 03cdbfa..9673ded 100644
--- a/src/cobalt/media/shell_video_data_allocator_common.h
+++ b/src/cobalt/media/shell_video_data_allocator_common.h
@@ -53,9 +53,13 @@
public:
explicit FrameBufferCommon(scoped_ptr<RawImageMemory> raw_image_memory);
- uint8* data() const OVERRIDE { return raw_image_memory_->GetMemory(); }
+ uint8* data() const OVERRIDE {
+ return raw_image_memory_ ? raw_image_memory_->GetMemory() : NULL;
+ }
- size_t size() const OVERRIDE { return raw_image_memory_->GetSizeInBytes(); }
+ size_t size() const OVERRIDE {
+ return raw_image_memory_ ? raw_image_memory_->GetSizeInBytes() : 0;
+ }
// Disown the image_data_.
scoped_ptr<RawImageMemory> DetachRawImageMemory();
diff --git a/src/cobalt/network/switches.cc b/src/cobalt/network/switches.cc
index 83bb9a7..158833f 100644
--- a/src/cobalt/network/switches.cc
+++ b/src/cobalt/network/switches.cc
@@ -20,7 +20,7 @@
namespace network {
namespace switches {
-#if defined(ENABLE_COMMAND_LINE_SWITCHES)
+#if defined(ENABLE_DEBUG_COMMAND_LINE_SWITCHES)
// Log network events using Chromium's network logger. If a parameter is
// specified, the parameter shall be interpreted as a file path and the network
// log will be written into the file. Otherwise, logging will be written to
@@ -30,7 +30,7 @@
// Corresponds to the levels described in the NetLog::LogLevel enum defined in
// net/base/net_log.h
const char kNetLogLevel[] = "net_log_level";
-#endif // ENABLE_COMMAND_LINE_SWITCHES
+#endif // ENABLE_DEBUG_COMMAND_LINE_SWITCHES
} // namespace switches
} // namespace network
diff --git a/src/cobalt/network/switches.h b/src/cobalt/network/switches.h
index 996c1d5..e95a70d 100644
--- a/src/cobalt/network/switches.h
+++ b/src/cobalt/network/switches.h
@@ -21,10 +21,10 @@
namespace network {
namespace switches {
-#if defined(ENABLE_COMMAND_LINE_SWITCHES)
+#if defined(ENABLE_DEBUG_COMMAND_LINE_SWITCHES)
extern const char kNetLog[];
extern const char kNetLogLevel[];
-#endif // ENABLE_COMMAND_LINE_SWITCHES
+#endif // ENABLE_DEBUG_COMMAND_LINE_SWITCHES
} // namespace switches
} // namespace network
diff --git a/src/cobalt/render_tree/animations/animate_node.cc b/src/cobalt/render_tree/animations/animate_node.cc
new file mode 100644
index 0000000..d51732a
--- /dev/null
+++ b/src/cobalt/render_tree/animations/animate_node.cc
@@ -0,0 +1,401 @@
+/*
+ * Copyright 2016 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 "cobalt/render_tree/animations/animate_node.h"
+
+#include "base/debug/trace_event.h"
+#include "cobalt/base/enable_if.h"
+#include "cobalt/base/polymorphic_downcast.h"
+#include "cobalt/render_tree/child_iterator.h"
+#include "cobalt/render_tree/node_visitor.h"
+
+namespace cobalt {
+namespace render_tree {
+namespace animations {
+
+void AnimateNode::Builder::AddInternal(
+ const scoped_refptr<Node>& target_node,
+ const scoped_refptr<AnimationListBase>& animation_list) {
+ DCHECK(node_animation_map_.find(target_node) == node_animation_map_.end())
+ << "The target render tree node already has an associated animation "
+ "list.";
+
+ node_animation_map_[target_node.get()] = animation_list;
+ node_refs_.push_back(target_node);
+}
+
+void AnimateNode::Builder::Merge(const AnimateNode::Builder& other) {
+#if !defined(NDEBUG)
+ for (InternalMap::const_iterator iter = node_animation_map_.begin();
+ iter != node_animation_map_.end(); ++iter) {
+ DCHECK(other.node_animation_map_.find(iter->first) ==
+ other.node_animation_map_.end())
+ << "Only mutually exclusive AnimateNode::Builders can be merged!";
+ }
+#endif
+ node_animation_map_.insert(other.node_animation_map_.begin(),
+ other.node_animation_map_.end());
+ node_refs_.insert(node_refs_.end(), other.node_refs_.begin(),
+ other.node_refs_.end());
+}
+
+// A helper render tree visitor class used to compile sub render-tree
+// animations. The same instance of the TraverseListBuilder class is reused for
+// traversing all nodes in a tree. After visiting a render tree,
+// |traverse_list_| will contain a post-order traversal of animated nodes where
+// children are visited from right to left, and this should be reversed to
+// obtain a pre-order traversal of animated nodes where children are visited
+// from left to right, which is much more natural.
+class AnimateNode::TraverseListBuilder : public NodeVisitor {
+ public:
+ TraverseListBuilder(const AnimateNode::Builder::InternalMap& animation_map,
+ TraverseList* traverse_list)
+ : animation_map_(animation_map), traverse_list_(traverse_list) {}
+
+ void Visit(animations::AnimateNode* animate) OVERRIDE;
+ void Visit(CompositionNode* composition) OVERRIDE { VisitNode(composition); }
+ void Visit(FilterNode* text) OVERRIDE { VisitNode(text); }
+ void Visit(ImageNode* image) OVERRIDE { VisitNode(image); }
+ void Visit(MatrixTransformNode* transform) OVERRIDE { VisitNode(transform); }
+ void Visit(PunchThroughVideoNode* punch_through) OVERRIDE {
+ VisitNode(punch_through);
+ }
+ void Visit(RectNode* rect) OVERRIDE { VisitNode(rect); }
+ void Visit(RectShadowNode* rect) OVERRIDE { VisitNode(rect); }
+ void Visit(TextNode* text) OVERRIDE { VisitNode(text); }
+
+ private:
+ template <typename T>
+ typename base::enable_if<!ChildIterator<T>::has_children>::type VisitNode(
+ T* node);
+
+ template <typename T>
+ typename base::enable_if<ChildIterator<T>::has_children>::type VisitNode(
+ T* node);
+ void ProcessNode(Node* node, bool animated_children);
+
+ // Adds a node to |traverse_list_|, indicating that it or its descendants are
+ // involved in animation.
+ void AddToTraverseList(
+ Node* node, AnimateNode::Builder::InternalMap::const_iterator found);
+
+ // A reference to the mapping from render tree node to animations.
+ const AnimateNode::Builder::InternalMap& animation_map_;
+
+ // A list of nodes that, if reversed, gives a pre-order traversal of only
+ // animated nodes.
+ // |traverse_list_| is the primary output of this visitor class.
+ TraverseList* traverse_list_;
+
+ // Signals to the caller of Visit() that this node was animated and so any
+ // parent nodes should also be added to the traversal list.
+ bool animated_;
+
+ // If non-null, references a node that this visitor's parent should replace
+ // this visitor's associated node with in its list of child nodes.
+ scoped_refptr<Node> replace_with_;
+
+ friend class AnimateNode;
+};
+
+void AnimateNode::TraverseListBuilder::Visit(animations::AnimateNode* animate) {
+ if (!animate->traverse_list_.empty()) {
+ // We merge all the information from this AnimateNode into the one we are
+ // constructing now. Simply append the sub-AnimateNode to |traverse_list_|,
+ // but reverse it so its finalized pre-order, left to right traversal is
+ // switched to the intermediate format of a post-order, right to left
+ // traversal.
+ size_t start_size = traverse_list_->size();
+ traverse_list_->insert(traverse_list_->end(),
+ animate->traverse_list_.begin(),
+ animate->traverse_list_.end());
+ std::reverse(traverse_list_->begin() + static_cast<int64>(start_size),
+ traverse_list_->end());
+ animated_ = true;
+ } else {
+ animated_ = false;
+ }
+
+ // Now that we have merged the sub-AnimateNode's information with the one
+ // under construction, remove this AnimateNode from the tree in order to
+ // maintain the invariant that an AnimateNode does not contain any
+ // AnimateNode descendants.
+ replace_with_ = animate->source_;
+}
+
+template <typename T>
+typename base::enable_if<!ChildIterator<T>::has_children>::type
+AnimateNode::TraverseListBuilder::VisitNode(T* node) {
+ // If we are dealing with a render tree node that has no children, all we
+ // need to do is call ProcessNode().
+ animated_ = false;
+ replace_with_ = NULL;
+ ProcessNode(node, false);
+}
+
+template <typename T>
+typename base::enable_if<ChildIterator<T>::has_children>::type
+AnimateNode::TraverseListBuilder::VisitNode(T* node) {
+ ChildIterator<T> child_iterator(node, kChildIteratorDirectionBackwards);
+ bool modified_children = false;
+ bool animated_children = false;
+ while (Node* child = child_iterator.GetCurrent()) {
+ child->Accept(this);
+
+ // Mark us as animated if any of our children are animated, so that we make
+ // sure to add ourselves to |traverse_list_|.
+ animated_children |= animated_;
+
+ if (replace_with_) {
+ // If the child node wishes to replace itself with a new node, then
+ // replace it within its parent's child list.
+ child_iterator.ReplaceCurrent(replace_with_);
+ modified_children = true;
+ }
+
+ child_iterator.Next();
+ }
+
+ if (modified_children) {
+ replace_with_ = new T(child_iterator.TakeReplacedChildrenBuilder());
+ } else {
+ replace_with_ = NULL;
+ }
+
+ // Finally, add this node to |traverse_list_| if it is animated either
+ // directly or indirectly (i.e. because its children are animated).
+ animated_ = false;
+ ProcessNode(node, animated_children);
+}
+
+void AnimateNode::TraverseListBuilder::ProcessNode(Node* node,
+ bool animated_children) {
+ // If this node is animated, add it to the |traverse_list_|.
+ AnimateNode::Builder::InternalMap::const_iterator found =
+ animation_map_.find(node);
+ if (animated_children || found != animation_map_.end()) {
+ AddToTraverseList(replace_with_ ? replace_with_.get() : node, found);
+ }
+}
+
+// Adds a node to |traverse_list_| so that it can be quickly
+// found in the future.
+void AnimateNode::TraverseListBuilder::AddToTraverseList(
+ Node* node, AnimateNode::Builder::InternalMap::const_iterator found) {
+ if (found != animation_map_.end()) {
+ traverse_list_->push_back(TraverseListEntry(node, found->second));
+ } else {
+ traverse_list_->push_back(TraverseListEntry(node));
+ }
+ animated_ = true;
+}
+
+// A helper render tree visitor class used to apply compiled sub render-tree
+// animations. Only one of these visitors is needed to visit an entire render
+// tree.
+class AnimateNode::ApplyVisitor : public NodeVisitor {
+ public:
+ ApplyVisitor(const TraverseList& traverse_list, base::TimeDelta time_offset);
+
+ void Visit(animations::AnimateNode* /* animate */) OVERRIDE {
+ // An invariant of AnimateNodes is that they should never contain descendant
+ // AnimateNodes.
+ NOTREACHED();
+ }
+ // Immediately switch to a templated visitor function.
+ void Visit(CompositionNode* composition) OVERRIDE { VisitNode(composition); }
+ void Visit(FilterNode* text) OVERRIDE { VisitNode(text); }
+ void Visit(ImageNode* image) OVERRIDE { VisitNode(image); }
+ void Visit(MatrixTransformNode* transform) OVERRIDE { VisitNode(transform); }
+ void Visit(PunchThroughVideoNode* punch_through) OVERRIDE {
+ VisitNode(punch_through);
+ }
+ void Visit(RectNode* rect) OVERRIDE { VisitNode(rect); }
+ void Visit(RectShadowNode* rect) OVERRIDE { VisitNode(rect); }
+ void Visit(TextNode* text) OVERRIDE { VisitNode(text); }
+
+ // Returns the animated version of the node last visited. This is how the
+ // final animated result can be pulled from this visitor.
+ const scoped_refptr<Node>& animated() const { return animated_; }
+
+ private:
+ template <typename T>
+ typename base::enable_if<!ChildIterator<T>::has_children>::type VisitNode(
+ T* node);
+ template <typename T>
+ typename base::enable_if<ChildIterator<T>::has_children>::type VisitNode(
+ T* node);
+ template <typename T>
+ void ApplyAnimations(const TraverseListEntry& entry,
+ typename T::Builder* builder);
+ TraverseListEntry AdvanceIterator(Node* node);
+
+ // The time offset to be passed in to individual animations.
+ base::TimeDelta time_offset_;
+ // The animated version of the last node visited.
+ scoped_refptr<Node> animated_;
+ // A list of nodes that we are allowed to traverse into (i.e. a traversal that
+ // guides us to animated nodes). It assumes that a pre-order traversal will
+ // be taken.
+ const TraverseList& traverse_list_;
+ // An iterator pointing to the next valid render tree node to visit.
+ TraverseList::const_iterator iterator_;
+};
+
+AnimateNode::ApplyVisitor::ApplyVisitor(const TraverseList& traverse_list,
+ base::TimeDelta time_offset)
+ : time_offset_(time_offset), traverse_list_(traverse_list) {
+ iterator_ = traverse_list_.begin();
+}
+
+template <typename T>
+typename base::enable_if<!ChildIterator<T>::has_children>::type
+AnimateNode::ApplyVisitor::VisitNode(T* node) {
+ TraverseListEntry current_entry = AdvanceIterator(node);
+ // If we don't have any children, then for this node to be visited, we must
+ // have animations.
+ DCHECK(current_entry.animations);
+ typename T::Builder builder(node->data());
+ ApplyAnimations<T>(current_entry, &builder);
+ animated_ = new T(builder);
+}
+
+template <typename T>
+typename base::enable_if<ChildIterator<T>::has_children>::type
+AnimateNode::ApplyVisitor::VisitNode(T* node) {
+ TraverseListEntry current_entry = AdvanceIterator(node);
+
+ // Traverse the child nodes, but only the ones that are on the
+ // |traverse_list_|. In particular, the next node we are allowed to visit
+ // is the one in the traverse list pointed to by |iterator_->node|.
+ ChildIterator<T> child_iterator(node);
+ bool children_modified = false;
+ while (Node* child = child_iterator.GetCurrent()) {
+ if (iterator_ == traverse_list_.end()) {
+ // If we've reached the end of |traverse_list_| then we are done
+ // iterating and it's time to return.
+ break;
+ }
+
+ if (child == iterator_->node) {
+ // If one of our children is next up on the path to animation, traverse
+ // into it.
+ child->Accept(this);
+ // Traversing into the child means that it was animated, and so replaced
+ // by an animated node while it was visited. Thus, replace it in the
+ // current node's child list with its animated version.
+ child_iterator.ReplaceCurrent(animated_);
+ children_modified = true;
+ }
+
+ child_iterator.Next();
+ }
+
+ if (current_entry.animations) {
+ base::optional<typename T::Builder> builder;
+ if (children_modified) {
+ // Reuse the modified Builder object from child traversal if one of
+ // our children was animated.
+ builder.emplace(child_iterator.TakeReplacedChildrenBuilder());
+ } else {
+ // Create a fresh copy of the Builder object for this animated node, to
+ // be passed into the animations.
+ builder.emplace(node->data());
+ }
+ ApplyAnimations<T>(current_entry, &(*builder));
+ animated_ = new T(*builder);
+ } else {
+ // If there were no animations targeting this node directly, then its
+ // children must have been modified since otherwise it wouldn't be in
+ // the traverse list.
+ DCHECK(children_modified);
+ animated_ = new T(child_iterator.TakeReplacedChildrenBuilder());
+ }
+}
+
+template <typename T>
+void AnimateNode::ApplyVisitor::ApplyAnimations(const TraverseListEntry& entry,
+ typename T::Builder* builder) {
+ TRACE_EVENT0("cobalt::renderer",
+ "AnimateNode::ApplyVisitor::ApplyAnimations()");
+ // Cast to the specific type we expect these animations to have.
+ const AnimationList<T>* typed_node_animations =
+ base::polymorphic_downcast<const AnimationList<T>*>(
+ entry.animations.get());
+
+ // Iterate through each animation applying them one at a time.
+ for (typename AnimationList<T>::InternalList::const_iterator iter =
+ typed_node_animations->data().animations.begin();
+ iter != typed_node_animations->data().animations.end(); ++iter) {
+ iter->Run(builder, time_offset_);
+ }
+}
+
+AnimateNode::TraverseListEntry AnimateNode::ApplyVisitor::AdvanceIterator(
+ Node* node) {
+ // Check that the iterator that we are advancing past is indeed the one we
+ // expect it to be.
+ DCHECK_EQ(node, iterator_->node);
+ return *(iterator_++);
+}
+
+AnimateNode::AnimateNode(const Builder& builder,
+ const scoped_refptr<Node>& source) {
+ TRACE_EVENT0("cobalt::renderer", "AnimateNode::AnimateNode(builder, source)");
+ CommonInit(builder.node_animation_map_, source);
+}
+
+AnimateNode::AnimateNode(const scoped_refptr<Node>& source) {
+ TRACE_EVENT0("cobalt::renderer", "AnimateNode::AnimateNode(source)");
+ CommonInit(Builder::InternalMap(), source);
+}
+
+scoped_refptr<Node> AnimateNode::Apply(base::TimeDelta time_offset) {
+ TRACE_EVENT0("cobalt::renderer", "AnimateNode::Apply()");
+ if (traverse_list_.empty()) {
+ return source_;
+ } else {
+ ApplyVisitor apply_visitor(traverse_list_, time_offset);
+ source_->Accept(&apply_visitor);
+ return apply_visitor.animated();
+ }
+}
+
+void AnimateNode::CommonInit(const Builder::InternalMap& node_animation_map,
+ const scoped_refptr<Node>& source) {
+ TraverseListBuilder traverse_list_builder(node_animation_map,
+ &traverse_list_);
+ source->Accept(&traverse_list_builder);
+
+ if (traverse_list_builder.replace_with_) {
+ source_ = traverse_list_builder.replace_with_;
+ } else {
+ source_ = source;
+ }
+
+ if (!traverse_list_.empty()) {
+ // We must adjust the resulting |traverse_list_| from an awkward
+ // intermediate format of post-order right to left traversal to the more
+ // natural pre-order left to right traversal expected by ApplyVisitor.
+ // This can be done by simply reversing the list.
+ std::reverse(traverse_list_.begin(), traverse_list_.end());
+ DCHECK(source_.get() == traverse_list_.begin()->node);
+ }
+}
+
+} // namespace animations
+} // namespace render_tree
+} // namespace cobalt
diff --git a/src/cobalt/render_tree/animations/animate_node.h b/src/cobalt/render_tree/animations/animate_node.h
new file mode 100644
index 0000000..4b9bfae
--- /dev/null
+++ b/src/cobalt/render_tree/animations/animate_node.h
@@ -0,0 +1,177 @@
+/*
+ * Copyright 2016 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.
+ */
+
+#ifndef COBALT_RENDER_TREE_ANIMATIONS_ANIMATE_NODE_H_
+#define COBALT_RENDER_TREE_ANIMATIONS_ANIMATE_NODE_H_
+
+#include <map>
+#include <vector>
+
+#include "base/containers/small_map.h"
+#include "base/memory/ref_counted.h"
+#include "cobalt/render_tree/animations/animation_list.h"
+#include "cobalt/render_tree/movable.h"
+#include "cobalt/render_tree/node.h"
+#include "cobalt/render_tree/node_visitor.h"
+
+namespace cobalt {
+namespace render_tree {
+namespace animations {
+
+// An AnimateNode describes a set of animations that affect the subtree attached
+// to the AnimateNode. In order to create an AnimateNode, one must first
+// populate an AnimateNode::Builder with a mapping of render tree node
+// references to corresponding animations that should be applied to them.
+// Construction of an AnimateNode object requires a populated
+// AnimateNode::Builder instance as well as the sub-tree that the animations
+// apply to. Upon construction, AnimateNode will compile the set of animated
+// nodes into a format specialized to the associated subtree such that it is
+// much faster to apply the animations. Once an AnimateNode is constructed,
+// it can generate static render trees representing frames of animation via
+// calls to AnimateNode::Apply(), which returns a static render tree.
+// When AnimateNodes are constructed they maintain an invariant that
+// AnimateNodes never have other AnimateNodes as descendants. It does this
+// by traversing the subtree on construction and if another AnimateNode is
+// encountered, its information is merged into this root AnimateNode, and the
+// sub-AnimateNode is removed from the tree.
+class AnimateNode : public Node {
+ public:
+ // Manages a mapping of render tree nodes to corresponding animations. Users
+ // of AnimateNode should populate the Builder with animations and then use
+ // that to construct the AnimateNode.
+ class Builder {
+ public:
+ DECLARE_AS_MOVABLE(Builder);
+
+ Builder() {}
+ explicit Builder(Moved moved) {
+ node_animation_map_ = moved->node_animation_map_;
+ node_refs_.swap(moved->node_refs_);
+ }
+
+ // This method is a template so that we can ensure that animations are not
+ // mismatched with render tree nodes of the wrong type.
+ template <typename T>
+ void Add(const scoped_refptr<T>& target_node,
+ const scoped_refptr<AnimationList<T> >& animation_list) {
+ AddInternal(target_node, animation_list);
+ }
+
+ // Convenience method to attach a single animation to a target node.
+ template <typename T>
+ void Add(const scoped_refptr<T>& target_node,
+ const typename Animation<T>::Function& single_animation) {
+ AddInternal(target_node, scoped_refptr<AnimationListBase>(
+ new AnimationList<T>(single_animation)));
+ }
+
+ // Merge all mappings from another AnimateNode::Builder into this one.
+ // There cannot be any keys that are in both the merge target and source.
+ void Merge(const Builder& other);
+
+ // Returns true if there are no animations added to this
+ // AnimateNode::Builder.
+ bool empty() const { return node_animation_map_.empty(); }
+
+ private:
+ // A non-template function that contains the logic for storing a target
+ // node and animation list pair.
+ void AddInternal(const scoped_refptr<Node>& target_node,
+ const scoped_refptr<AnimationListBase>& animation_list);
+
+ // The primary internal data structure used to organize and store the
+ // mapping between target render tree node and animation list.
+ // In many cases there are not many active animations, and so we use a
+ // base::SmallMap for this. std::map was found to be more performant than
+ // base::hash_map, so it is used as the fallback map.
+ typedef base::SmallMap<std::map<Node*, scoped_refptr<AnimationListBase> >,
+ 4> InternalMap;
+ InternalMap node_animation_map_;
+ std::vector<scoped_refptr<Node> > node_refs_;
+
+ friend class AnimateNode;
+ };
+
+ AnimateNode(const Builder& builder, const scoped_refptr<Node>& source);
+
+ // This will create an AnimateNode with no animations. It is useful because
+ // construction of AnimateNodes maintain an invariant that there are no
+ // sub-AnimateNodes underneath them. Thus, adding a AnimateNode, even if it
+ // has no animations, to an existing tree will result in existing AnimateNodes
+ // being merged into the new root AnimateNode, which can simplify the
+ // underlying tree.
+ explicit AnimateNode(const scoped_refptr<Node>& source);
+
+ // Cannot visit this node.
+ void Accept(NodeVisitor* visitor) OVERRIDE { visitor->Visit(this); }
+
+ // Since we don't have any bounds on the animations contained in this tree,
+ // we cannot know the bounds of the tree over all time. Indeed animations
+ // may not have any bounds as time goes to infinity. Despite this, we return
+ // the bounds of the initial render tree to enable AnimateNodes to be setup
+ // as children of CompositionNodes.
+ math::RectF GetBounds() const OVERRIDE { return source_->GetBounds(); }
+
+ base::TypeId GetTypeId() const OVERRIDE {
+ return base::GetTypeId<AnimateNode>();
+ }
+
+ // Apply the animations to the sub render tree with the given |time_offset|.
+ // An animated sub-tree is returned, which is guaranteed to not contain any
+ // AnimateNodes.
+ scoped_refptr<Node> Apply(base::TimeDelta time_offset);
+
+ // Returns the sub-tree for which the animations apply to.
+ const scoped_refptr<Node> source() const { return source_; }
+
+ private:
+ // A helper render tree visitor class used to compile sub render-tree
+ // animations.
+ class TraverseListBuilder;
+ // A helper render tree visitor class used to apply compiled sub render-tree
+ // animations. This class follows the traversal generated by
+ // TraverseListBuilder.
+ class ApplyVisitor;
+
+ void CommonInit(const Builder::InternalMap& node_animation_map,
+ const scoped_refptr<Node>& source);
+
+ // The compiled node animation list is a sequence of nodes that are either
+ // animated themselves, or on the path to an animated node. Only nodes in
+ // this sequence need to be traversed. TraverseListEntry is an entry in this
+ // list, complete with animations to be applied to the given node, if any.
+ struct TraverseListEntry {
+ TraverseListEntry(Node* node,
+ const scoped_refptr<AnimationListBase>& animations)
+ : node(node), animations(animations) {}
+ explicit TraverseListEntry(Node* node) : node(node) {}
+
+ Node* node;
+ scoped_refptr<AnimationListBase> animations;
+ };
+ typedef std::vector<TraverseListEntry> TraverseList;
+
+ // The compiled traversal list through the sub-tree represented by |source_|
+ // that guides us towards all nodes that need to be animated.
+ TraverseList traverse_list_;
+ scoped_refptr<Node> source_;
+};
+
+} // namespace animations
+} // namespace render_tree
+} // namespace cobalt
+
+#endif // COBALT_RENDER_TREE_ANIMATIONS_ANIMATE_NODE_H_
diff --git a/src/cobalt/render_tree/animations/node_animations_map_test.cc b/src/cobalt/render_tree/animations/animate_node_test.cc
similarity index 67%
rename from src/cobalt/render_tree/animations/node_animations_map_test.cc
rename to src/cobalt/render_tree/animations/animate_node_test.cc
index 5e45af5..f46e63e 100644
--- a/src/cobalt/render_tree/animations/node_animations_map_test.cc
+++ b/src/cobalt/render_tree/animations/animate_node_test.cc
@@ -1,5 +1,5 @@
/*
- * Copyright 2015 Google Inc. All Rights Reserved.
+ * Copyright 2016 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.
@@ -21,7 +21,7 @@
#include "cobalt/math/rect_f.h"
#include "cobalt/math/size_f.h"
#include "cobalt/math/transform_2d.h"
-#include "cobalt/render_tree/animations/node_animations_map.h"
+#include "cobalt/render_tree/animations/animate_node.h"
#include "cobalt/render_tree/brush.h"
#include "cobalt/render_tree/color_rgba.h"
#include "cobalt/render_tree/composition_node.h"
@@ -46,12 +46,12 @@
// Helper function to create an animation set for a render tree that consists
// of only one animation targeting only one node in the render tree.
template <typename T>
-scoped_refptr<NodeAnimationsMap> CreateSingleAnimation(
+scoped_refptr<AnimateNode> CreateSingleAnimation(
const scoped_refptr<T>& target,
typename Animation<T>::Function anim_function) {
- NodeAnimationsMap::Builder animations_builder;
+ AnimateNode::Builder animations_builder;
animations_builder.Add(target, anim_function);
- return new NodeAnimationsMap(animations_builder.Pass());
+ return new AnimateNode(animations_builder, target);
}
class ImageFake : public Image {
@@ -68,16 +68,16 @@
UNREFERENCED_PARAMETER(time_elapsed);
text_node->color = ColorRGBA(.5f, .5f, .5f);
}
-TEST(NodeAnimationsMapTest, EnsureSingleTextNodeAnimates) {
+TEST(AnimateNodeTest, EnsureSingleTextNodeAnimates) {
scoped_refptr<TextNode> text_node(
new TextNode(math::Vector2dF(0, 0), new GlyphBuffer(RectF(0, 0, 1, 1)),
ColorRGBA(1.0f, 1.0f, 1.0f)));
- scoped_refptr<NodeAnimationsMap> animations =
+ scoped_refptr<AnimateNode> with_animations =
CreateSingleAnimation(text_node, base::Bind(&AnimateText));
scoped_refptr<Node> animated_render_tree =
- animations->Apply(text_node, base::TimeDelta::FromSeconds(1));
+ with_animations->Apply(base::TimeDelta::FromSeconds(1));
TextNode* animated_text_node =
dynamic_cast<TextNode*>(animated_render_tree.get());
EXPECT_TRUE(animated_text_node);
@@ -89,15 +89,15 @@
UNREFERENCED_PARAMETER(time_elapsed);
image_node->destination_rect = RectF(2.0f, 2.0f);
}
-TEST(NodeAnimationsMapTest, EnsureSingleImageNodeAnimates) {
+TEST(AnimateNodeTest, EnsureSingleImageNodeAnimates) {
scoped_refptr<ImageNode> image_node(
new ImageNode(make_scoped_refptr(new ImageFake()), RectF(1.0f, 1.0f)));
- scoped_refptr<NodeAnimationsMap> animations =
+ scoped_refptr<AnimateNode> with_animations =
CreateSingleAnimation(image_node, base::Bind(&AnimateImage));
scoped_refptr<Node> animated_render_tree =
- animations->Apply(image_node, base::TimeDelta::FromSeconds(1));
+ with_animations->Apply(base::TimeDelta::FromSeconds(1));
ImageNode* animated_image_node =
dynamic_cast<ImageNode*>(animated_render_tree.get());
EXPECT_TRUE(animated_image_node);
@@ -109,16 +109,16 @@
UNREFERENCED_PARAMETER(time_elapsed);
rect_node->rect = RectF(2.0f, 2.0f);
}
-TEST(NodeAnimationsMapTest, EnsureSingleRectNodeAnimates) {
+TEST(AnimateNodeTest, EnsureSingleRectNodeAnimates) {
scoped_refptr<RectNode> rect_node(new RectNode(
RectF(1.0f, 1.0f),
scoped_ptr<Brush>(new SolidColorBrush(ColorRGBA(1.0f, 1.0f, 1.0f)))));
- scoped_refptr<NodeAnimationsMap> animations =
+ scoped_refptr<AnimateNode> with_animations =
CreateSingleAnimation(rect_node, base::Bind(&AnimateRect));
scoped_refptr<Node> animated_render_tree =
- animations->Apply(rect_node, base::TimeDelta::FromSeconds(1));
+ with_animations->Apply(base::TimeDelta::FromSeconds(1));
RectNode* animated_rect_node =
dynamic_cast<RectNode*>(animated_render_tree.get());
EXPECT_TRUE(animated_rect_node);
@@ -135,33 +135,32 @@
static_cast<float>(time_elapsed.InSecondsF()),
static_cast<float>(time_elapsed.InSecondsF()));
}
-TEST(NodeAnimationsMapTest,
- SingleImageNodeAnimatesOverTimeRepeatedlyCorrectly) {
+TEST(AnimateNodeTest, SingleImageNodeAnimatesOverTimeRepeatedlyCorrectly) {
scoped_refptr<ImageNode> image_node(
new ImageNode(make_scoped_refptr(new ImageFake()), RectF(1.0f, 1.0f)));
- scoped_refptr<NodeAnimationsMap> animations =
+ scoped_refptr<AnimateNode> with_animations =
CreateSingleAnimation(image_node, base::Bind(&AnimateImageAddWithTime));
scoped_refptr<Node> animated_render_tree;
ImageNode* animated_image_node;
animated_render_tree =
- animations->Apply(image_node, base::TimeDelta::FromSeconds(1));
+ with_animations->Apply(base::TimeDelta::FromSeconds(1));
animated_image_node = dynamic_cast<ImageNode*>(animated_render_tree.get());
EXPECT_TRUE(animated_image_node);
EXPECT_TRUE(animated_image_node);
EXPECT_FLOAT_EQ(3.0f, animated_image_node->data().destination_rect.width());
animated_render_tree =
- animations->Apply(image_node, base::TimeDelta::FromSeconds(2));
+ with_animations->Apply(base::TimeDelta::FromSeconds(2));
animated_image_node = dynamic_cast<ImageNode*>(animated_render_tree.get());
EXPECT_TRUE(animated_image_node);
EXPECT_TRUE(animated_image_node);
EXPECT_FLOAT_EQ(5.0f, animated_image_node->data().destination_rect.width());
animated_render_tree =
- animations->Apply(image_node, base::TimeDelta::FromSeconds(4));
+ with_animations->Apply(base::TimeDelta::FromSeconds(4));
animated_image_node = dynamic_cast<ImageNode*>(animated_render_tree.get());
EXPECT_TRUE(animated_image_node);
EXPECT_TRUE(animated_image_node);
@@ -177,8 +176,7 @@
static_cast<float>(time_elapsed.InSecondsF()));
image_node->destination_rect.set_size(image_size);
}
-TEST(NodeAnimationsMapTest,
- MultipleAnimationsTargetingOneNodeApplyInCorrectOrder) {
+TEST(AnimateNodeTest, MultipleAnimationsTargetingOneNodeApplyInCorrectOrder) {
scoped_refptr<ImageNode> image_node(
new ImageNode(make_scoped_refptr(new ImageFake()), RectF(1.0f, 1.0f)));
@@ -192,15 +190,15 @@
animation_list_builder.animations.push_back(
base::Bind(&AnimateImageScaleWithTime));
- NodeAnimationsMap::Builder animations_builder;
+ AnimateNode::Builder animations_builder;
animations_builder.Add(image_node,
make_scoped_refptr(new AnimationList<ImageNode>(
animation_list_builder.Pass())));
- scoped_refptr<NodeAnimationsMap> animations(
- new NodeAnimationsMap(animations_builder.Pass()));
+ scoped_refptr<AnimateNode> with_animations(
+ new AnimateNode(animations_builder, image_node));
scoped_refptr<Node> animated_render_tree =
- animations->Apply(image_node, base::TimeDelta::FromSeconds(3));
+ with_animations->Apply(base::TimeDelta::FromSeconds(3));
ImageNode* animated_image_node =
dynamic_cast<ImageNode*>(animated_render_tree.get());
@@ -216,22 +214,21 @@
UNREFERENCED_PARAMETER(time_elapsed);
transform_node->transform = math::TranslateMatrix(2.0f, 2.0f);
}
-TEST(NodeAnimationsMapTest, AnimatingTransformNodeDoesNotAffectSourceChild) {
+TEST(AnimateNodeTest, AnimatingTransformNodeDoesNotAffectSourceChild) {
scoped_refptr<ImageNode> image_node(
new ImageNode(make_scoped_refptr(new ImageFake()), RectF(1.0f, 1.0f)));
scoped_refptr<MatrixTransformNode> transform_node(
new MatrixTransformNode(image_node, math::Matrix3F::Identity()));
- scoped_refptr<NodeAnimationsMap> animations =
+ scoped_refptr<AnimateNode> with_animations =
CreateSingleAnimation(transform_node, base::Bind(&AnimateTransform));
scoped_refptr<Node> animated_render_tree =
- animations->Apply(transform_node, base::TimeDelta::FromSeconds(1));
+ with_animations->Apply(base::TimeDelta::FromSeconds(1));
MatrixTransformNode* animated_transform_node =
dynamic_cast<MatrixTransformNode*>(animated_render_tree.get());
EXPECT_TRUE(animated_transform_node);
- EXPECT_TRUE(animated_transform_node);
EXPECT_EQ(math::TranslateMatrix(2.0f, 2.0f),
animated_transform_node->data().transform);
@@ -241,7 +238,7 @@
// Test that animating a child correctly adjusts sub-node parameters but
// not parent node parameters, though both child and parent are different nodes
// now. The animated child's sibling should be left untouched.
-TEST(NodeAnimationsMapTest,
+TEST(AnimateNodeTest,
AnimatingCompositionChildNodeAffectsParentAsWellButNotSibling) {
scoped_refptr<ImageNode> image_node_a(
new ImageNode(make_scoped_refptr(new ImageFake()), RectF(1.0f, 1.0f)));
@@ -253,11 +250,13 @@
scoped_refptr<CompositionNode> composition_node(
new CompositionNode(composition_node_builder.Pass()));
- scoped_refptr<NodeAnimationsMap> animations =
- CreateSingleAnimation(image_node_a, base::Bind(&AnimateImage));
+ AnimateNode::Builder animation_builder;
+ animation_builder.Add(image_node_a, base::Bind(&AnimateImage));
+ scoped_refptr<AnimateNode> with_animations =
+ new AnimateNode(animation_builder, composition_node);
scoped_refptr<Node> animated_render_tree =
- animations->Apply(composition_node, base::TimeDelta::FromSeconds(1));
+ with_animations->Apply(base::TimeDelta::FromSeconds(1));
CompositionNode* animated_composition_node =
dynamic_cast<CompositionNode*>(animated_render_tree.get());
@@ -273,6 +272,76 @@
EXPECT_EQ(image_node_b.get(), animated_image_node_b);
}
+TEST(AnimateNodeTest, SimpleSubAnimateNode) {
+ // Test that we can properly animate trees that built upon multiple
+ // AnimateNodes.
+ scoped_refptr<ImageNode> image_node(
+ new ImageNode(make_scoped_refptr(new ImageFake()), RectF(1.0f, 1.0f)));
+ scoped_refptr<AnimateNode> image_animation =
+ CreateSingleAnimation(image_node, base::Bind(&AnimateImage));
+
+ scoped_refptr<MatrixTransformNode> transform_node(
+ new MatrixTransformNode(image_animation, math::Matrix3F::Identity()));
+
+ scoped_refptr<AnimateNode> with_animations =
+ CreateSingleAnimation(transform_node, base::Bind(&AnimateTransform));
+
+ scoped_refptr<Node> animated_render_tree =
+ with_animations->Apply(base::TimeDelta::FromSeconds(1));
+
+ MatrixTransformNode* animated_transform_node =
+ dynamic_cast<MatrixTransformNode*>(animated_render_tree.get());
+ EXPECT_TRUE(animated_transform_node);
+
+ // Check that the matrix transform node is animated.
+ EXPECT_EQ(math::TranslateMatrix(2.0f, 2.0f),
+ animated_transform_node->data().transform);
+
+ // Check also that the image node is animated.
+ ImageNode* animated_image_node =
+ dynamic_cast<ImageNode*>(animated_transform_node->data().source.get());
+ EXPECT_TRUE(animated_image_node);
+ EXPECT_EQ(RectF(2.0f, 2.0f), animated_image_node->data().destination_rect);
+}
+
+TEST(AnimateNodeTest, SubAnimateNodeWithTwoAncestors) {
+ // Test that we can properly animate trees that built upon multiple
+ // AnimateNodes.
+ scoped_refptr<ImageNode> image_node(
+ new ImageNode(make_scoped_refptr(new ImageFake()), RectF(1.0f, 1.0f)));
+ scoped_refptr<AnimateNode> image_animation =
+ CreateSingleAnimation(image_node, base::Bind(&AnimateImage));
+
+ // This node is used to make it so there is more than one node on the path
+ // between the two AnimateNodes.
+ scoped_refptr<MatrixTransformNode> transform_node_a(
+ new MatrixTransformNode(image_animation, math::Matrix3F::Identity()));
+
+ scoped_refptr<MatrixTransformNode> transform_node_b(
+ new MatrixTransformNode(transform_node_a, math::Matrix3F::Identity()));
+
+ scoped_refptr<AnimateNode> with_animations =
+ new AnimateNode(transform_node_b);
+
+ scoped_refptr<Node> animated_render_tree =
+ with_animations->Apply(base::TimeDelta::FromSeconds(1));
+
+ MatrixTransformNode* animated_transform_node =
+ dynamic_cast<MatrixTransformNode*>(animated_render_tree.get());
+ EXPECT_TRUE(animated_transform_node);
+
+ // Check that the image node is animated.
+ MatrixTransformNode* animated_dummy_transform_node =
+ dynamic_cast<MatrixTransformNode*>(
+ animated_transform_node->data().source.get());
+ EXPECT_TRUE(animated_dummy_transform_node);
+
+ ImageNode* animated_image_node = dynamic_cast<ImageNode*>(
+ animated_dummy_transform_node->data().source.get());
+ EXPECT_TRUE(animated_image_node);
+ EXPECT_EQ(RectF(2.0f, 2.0f), animated_image_node->data().destination_rect);
+}
+
} // namespace animations
} // namespace render_tree
} // namespace cobalt
diff --git a/src/cobalt/render_tree/animations/animation_list.h b/src/cobalt/render_tree/animations/animation_list.h
index 8c83f36..a37bd3f 100644
--- a/src/cobalt/render_tree/animations/animation_list.h
+++ b/src/cobalt/render_tree/animations/animation_list.h
@@ -67,7 +67,7 @@
// base::TimeDelta::FromSeconds(1)));
//
// You can now create an AnimationList object from the AnimationList::Builder
- // and ultimately add that to a NodeAnimationsMap object so that it can be
+ // and ultimately add that to a AnimateNode::Builder object so that it can be
// mapped to a specific TextNode that it should be applied to.
typedef base::Callback<void(typename T::Builder*, base::TimeDelta)> Function;
};
diff --git a/src/cobalt/render_tree/animations/node_animations_map.cc b/src/cobalt/render_tree/animations/node_animations_map.cc
deleted file mode 100644
index c123536..0000000
--- a/src/cobalt/render_tree/animations/node_animations_map.cc
+++ /dev/null
@@ -1,314 +0,0 @@
-/*
- * Copyright 2015 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 "cobalt/render_tree/animations/node_animations_map.h"
-
-#include "base/debug/trace_event.h"
-#include "base/optional.h"
-#include "cobalt/base/polymorphic_downcast.h"
-#include "cobalt/render_tree/composition_node.h"
-#include "cobalt/render_tree/filter_node.h"
-#include "cobalt/render_tree/image_node.h"
-#include "cobalt/render_tree/matrix_transform_node.h"
-#include "cobalt/render_tree/node_visitor.h"
-#include "cobalt/render_tree/punch_through_video_node.h"
-#include "cobalt/render_tree/rect_node.h"
-#include "cobalt/render_tree/rect_shadow_node.h"
-#include "cobalt/render_tree/text_node.h"
-
-namespace cobalt {
-namespace render_tree {
-namespace animations {
-
-void NodeAnimationsMap::Builder::AddInternal(
- const scoped_refptr<Node>& target_node,
- const scoped_refptr<AnimationListBase>& animation_list) {
- DCHECK(node_animation_map_.find(target_node) == node_animation_map_.end())
- << "The target render tree node already has an associated animation "
- "list.";
-
- node_animation_map_[target_node.get()] = animation_list;
- node_refs_.push_back(target_node);
-}
-
-void NodeAnimationsMap::Builder::Merge(
- const NodeAnimationsMap::Builder& other) {
-#if !defined(NDEBUG)
- for (InternalMap::const_iterator iter = node_animation_map_.begin();
- iter != node_animation_map_.end(); ++iter) {
- DCHECK(other.node_animation_map_.find(iter->first) ==
- other.node_animation_map_.end()) <<
- "Only mutually exclusive NodeAnimationMaps can be merged!";
- }
-#endif
- node_animation_map_.insert(
- other.node_animation_map_.begin(), other.node_animation_map_.end());
- node_refs_.insert(
- node_refs_.end(), other.node_refs_.begin(), other.node_refs_.end());
-}
-
-AnimationListBase* NodeAnimationsMap::GetAnimationsForNode(Node* target) const {
- Builder::InternalMap::const_iterator found =
- data_.node_animation_map_.find(target);
- if (found == data_.node_animation_map_.end()) return NULL;
- return found->second.get();
-}
-
-// This visitor object contains the logic for how to apply animation to each
-// render tree node. Things are most interesting for node types that may
-// contain child render tree nodes, like CompositionNode. In this case,
-// they will need to be animated not only if animations directly affect them,
-// but also if any of their children have been animated.
-class NodeAnimationsMap::NodeVisitor : public render_tree::NodeVisitor {
- public:
- explicit NodeVisitor(const NodeAnimationsMap& animations,
- const base::TimeDelta& time_elapsed);
-
- void Visit(CompositionNode* composition_node) OVERRIDE;
- void Visit(FilterNode* image_node) OVERRIDE;
- void Visit(ImageNode* image_node) OVERRIDE;
- void Visit(MatrixTransformNode* matrix_transform_node) OVERRIDE;
- void Visit(PunchThroughVideoNode* punch_through_video_node) OVERRIDE;
- void Visit(RectNode* rect_node) OVERRIDE;
- void Visit(RectShadowNode* rect_shadow_node) OVERRIDE;
- void Visit(TextNode* text_node) OVERRIDE;
-
- bool has_animated_node() const { return !!animated_node_; }
-
- // NodeVisitor objects are intended to be "one-shot"
- // visit objects. The "return value" (e.g. the animated node) can be
- // retrieved by calling animated_node() after Visit() has been called.
- const scoped_refptr<Node>& animated_node() { return *animated_node_; }
-
- // Helper function to apply all animations in a AnimationList to a specific
- // node builder.
- template <typename T>
- static void ApplyAnimations(typename T::Builder* builder,
- const AnimationListBase* node_animations,
- base::TimeDelta time_elapsed);
-
- // Helper function for applying animations to simple nodes that don't have any
- // children or special cases.
- template <typename T>
- static base::optional<scoped_refptr<Node> >
- MaybeCloneLeafNodeAndApplyAnimations(
- T* node, const NodeAnimationsMap& animations,
- base::TimeDelta time_elapsed);
-
- private:
- const NodeAnimationsMap& animations_;
- const base::TimeDelta& time_elapsed_;
-
- base::optional<scoped_refptr<Node> > animated_node_;
-};
-
-NodeAnimationsMap::NodeVisitor::NodeVisitor(const NodeAnimationsMap& animations,
- const base::TimeDelta& time_elapsed)
- : animations_(animations), time_elapsed_(time_elapsed) {}
-
-template <typename T>
-void NodeAnimationsMap::NodeVisitor::ApplyAnimations(
- typename T::Builder* builder, const AnimationListBase* node_animations,
- base::TimeDelta time_elapsed) {
- // Cast to the specific type we expect these animations to have.
- const AnimationList<T>* typed_node_animations =
- base::polymorphic_downcast<const AnimationList<T>*>(node_animations);
-
- // Iterate through each animation applying them one at a time.
- for (typename AnimationList<T>::InternalList::const_iterator iter =
- typed_node_animations->data().animations.begin();
- iter != typed_node_animations->data().animations.end(); ++iter) {
- iter->Run(builder, time_elapsed);
- }
-}
-
-template <typename T>
-base::optional<scoped_refptr<Node> >
-NodeAnimationsMap::NodeVisitor::MaybeCloneLeafNodeAndApplyAnimations(
- T* node, const NodeAnimationsMap& animations,
- base::TimeDelta time_elapsed) {
- const AnimationListBase* node_animations =
- animations.GetAnimationsForNode(node);
- if (node_animations != NULL) {
- typename T::Builder builder(node->data());
-
- ApplyAnimations<T>(&builder, node_animations, time_elapsed);
-
- return scoped_refptr<Node>(new T(builder));
- } else {
- // No animations were applied to this node, return NULL to signify this.
- return base::nullopt;
- }
-}
-
-void NodeAnimationsMap::NodeVisitor::Visit(CompositionNode* composition_node) {
- // We declare the builder as an optional because we may not need one if we
- // have no animations and none of our children are animated.
- base::optional<CompositionNode::Builder> builder;
-
- const CompositionNode::Children& original_children =
- composition_node->data().children();
-
- // Iterate through our children and visit them to apply animations. After
- // each one, check to see if it actually was animated, and if so, replace
- // this composition node's reference to that child with the newly animated
- // one.
- for (size_t i = 0; i < original_children.size(); ++i) {
- NodeVisitor child_visitor(animations_, time_elapsed_);
- original_children[i]->Accept(&child_visitor);
-
- // If a child was animated, then we must adjust our child node reference to
- // the newly animated one.
- if (child_visitor.has_animated_node()) {
- if (!builder) {
- builder.emplace(composition_node->data());
- }
- *builder->GetChild(static_cast<int>(i)) = child_visitor.animated_node();
- }
- }
-
- // Check if any animations apply directly to us, and if so, apply them.
- const AnimationListBase* animations =
- animations_.GetAnimationsForNode(composition_node);
- if (animations != NULL) {
- if (!builder) {
- builder.emplace(composition_node->data());
- }
- ApplyAnimations<CompositionNode>(&builder.value(), animations,
- time_elapsed_);
- }
-
- // Return the animated node. If no animations took place, leave
- // animated_node_ as NULL to signify that no animations took place.
- if (builder) {
- animated_node_ = scoped_refptr<Node>(new CompositionNode(builder->Pass()));
- }
-}
-
-void NodeAnimationsMap::NodeVisitor::Visit(FilterNode* filter_node) {
- base::optional<FilterNode::Builder> builder;
-
- // First check to see if our source node has any animations, and if so,
- // animate it.
- NodeVisitor child_visitor(animations_, time_elapsed_);
- filter_node->data().source->Accept(&child_visitor);
-
- if (child_visitor.has_animated_node()) {
- // If our source node was animated, then so must we be, so create a
- // builder and set it up to point to our animated source node.
- builder.emplace(filter_node->data());
- builder->source = child_visitor.animated_node();
- }
-
- // Apply any animations to the filter node itself.
- const AnimationListBase* animations =
- animations_.GetAnimationsForNode(filter_node);
- if (animations != NULL) {
- if (!builder) {
- builder.emplace(filter_node->data());
- }
- ApplyAnimations<FilterNode>(&builder.value(), animations, time_elapsed_);
- }
-
- // Return the animated node. If no animations took place, leave
- // animated_node_ as NULL to signify that no animations took place.
- if (builder) {
- animated_node_ = scoped_refptr<Node>(new FilterNode(*builder));
- }
-}
-
-void NodeAnimationsMap::NodeVisitor::Visit(ImageNode* image_node) {
- animated_node_ = MaybeCloneLeafNodeAndApplyAnimations(
- image_node, animations_, time_elapsed_);
-}
-
-void NodeAnimationsMap::NodeVisitor::Visit(
- MatrixTransformNode* matrix_transform_node) {
- base::optional<MatrixTransformNode::Builder> builder;
-
- // First check to see if our source node has any animations, and if so,
- // animate it.
- NodeVisitor child_visitor(animations_, time_elapsed_);
- matrix_transform_node->data().source->Accept(&child_visitor);
-
- if (child_visitor.has_animated_node()) {
- // If our source node was animated, then so must we be, so create a
- // builder and set it up to point to our animated source node.
- builder.emplace(matrix_transform_node->data());
- builder->source = child_visitor.animated_node();
- }
-
- // Apply any animations to the filter node itself.
- const AnimationListBase* animations =
- animations_.GetAnimationsForNode(matrix_transform_node);
- if (animations != NULL) {
- if (!builder) {
- builder.emplace(matrix_transform_node->data());
- }
- ApplyAnimations<MatrixTransformNode>(&builder.value(), animations,
- time_elapsed_);
- }
-
- // Return the animated node. If no animations took place, leave
- // animated_node_ as NULL to signify that no animations took place.
- if (builder) {
- animated_node_ = scoped_refptr<Node>(new MatrixTransformNode(*builder));
- }
-}
-
-void NodeAnimationsMap::NodeVisitor::Visit(
- PunchThroughVideoNode* punch_through_video_node) {
- animated_node_ = MaybeCloneLeafNodeAndApplyAnimations(
- punch_through_video_node, animations_, time_elapsed_);
-}
-
-void NodeAnimationsMap::NodeVisitor::Visit(RectNode* rect_node) {
- // We do not use MaybeCloneLeafNodeAndApplyAnimations() here so that we can
- // construct our RectNode via a move of the RectNode::Builder object, instead
- // of a copy.
- const AnimationListBase* node_animations =
- animations_.GetAnimationsForNode(rect_node);
- if (node_animations != NULL) {
- RectNode::Builder builder(rect_node->data());
-
- ApplyAnimations<RectNode>(&builder, node_animations, time_elapsed_);
-
- // Move construct our RectNode from the RectNode::Builder object.
- animated_node_ = scoped_refptr<Node>(new RectNode(builder.Pass()));
- }
-}
-
-void NodeAnimationsMap::NodeVisitor::Visit(RectShadowNode* rect_shadow_node) {
- animated_node_ = MaybeCloneLeafNodeAndApplyAnimations(
- rect_shadow_node, animations_, time_elapsed_);
-}
-
-void NodeAnimationsMap::NodeVisitor::Visit(TextNode* text_node) {
- animated_node_ = MaybeCloneLeafNodeAndApplyAnimations(
- text_node, animations_, time_elapsed_);
-}
-
-scoped_refptr<Node> NodeAnimationsMap::Apply(const scoped_refptr<Node>& root,
- base::TimeDelta time_elapsed) {
- TRACE_EVENT0("cobalt::renderer", "NodeAnimationsMap::Apply()");
- NodeVisitor root_visitor(*this, time_elapsed);
- root->Accept(&root_visitor);
- return root_visitor.has_animated_node() ? root_visitor.animated_node() : root;
-}
-
-} // namespace animations
-} // namespace render_tree
-} // namespace cobalt
diff --git a/src/cobalt/render_tree/animations/node_animations_map.h b/src/cobalt/render_tree/animations/node_animations_map.h
deleted file mode 100644
index 669cd61..0000000
--- a/src/cobalt/render_tree/animations/node_animations_map.h
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- * Copyright 2015 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.
- */
-
-#ifndef COBALT_RENDER_TREE_ANIMATIONS_NODE_ANIMATIONS_MAP_H_
-#define COBALT_RENDER_TREE_ANIMATIONS_NODE_ANIMATIONS_MAP_H_
-
-#include <map>
-#include <vector>
-
-#include "base/containers/small_map.h"
-#include "base/memory/ref_counted.h"
-#include "cobalt/render_tree/animations/animation_list.h"
-#include "cobalt/render_tree/movable.h"
-#include "cobalt/render_tree/node.h"
-
-namespace cobalt {
-namespace render_tree {
-namespace animations {
-
-// A NodeAnimationsMap object represents a reference counted and immutable (so
-// they can be easily shared between threads) set of animations, along with
-// references to the render tree Nodes that they target. NodeAnimationsMap
-// objects contain animation information about corresponding render trees and
-// are intended to be passed alongside them to modules that would like to
-// animate render trees.
-// NodeAnimationsMap objects essentially organize their collections of
-// animations as an unordered map from render tree Node objects to
-// AnimationLists. Thus, animation can be applied to a render tree by traversing
-// it and for each element checking to see if any animations exist for them, and
-// if so, apply them. Indeed, the NodeAnimationsMap object's primary method,
-// Apply(), does just this.
-class NodeAnimationsMap : public base::RefCountedThreadSafe<NodeAnimationsMap> {
- public:
- // Use this NodeAnimationsMap::Builder object to construct your collection of
- // animations and corresponding render_tree Nodes. When setup is complete,
- // construct a NodeAnimationsMap object with the Builder.
- class Builder {
- public:
- DECLARE_AS_MOVABLE(Builder);
-
- Builder() {}
- explicit Builder(Moved moved) {
- node_animation_map_ = moved->node_animation_map_;
- node_refs_.swap(moved->node_refs_);
- }
-
- // This method is a template so that we can ensure that animations are not
- // mismatched with render tree nodes of the wrong type.
- template <typename T>
- void Add(const scoped_refptr<T>& target_node,
- const scoped_refptr<AnimationList<T> >& animation_list) {
- AddInternal(target_node, animation_list);
- }
-
- // Convenience method to attach a single animation to a target node.
- template <typename T>
- void Add(const scoped_refptr<T>& target_node,
- const typename Animation<T>::Function& single_animation) {
- AddInternal(target_node, scoped_refptr<AnimationListBase>(
- new AnimationList<T>(single_animation)));
- }
-
- // Merge all mappings from another NodeAnimationsMap into this one. There
- // cannot be any keys that are in both the merge target and source.
- void Merge(const NodeAnimationsMap& other) { Merge(other.data_); }
- void Merge(const NodeAnimationsMap::Builder& other);
-
- private:
- // A non-template function that contains the logic for storing a target
- // node and animation list pair.
- void AddInternal(const scoped_refptr<Node>& target_node,
- const scoped_refptr<AnimationListBase>& animation_list);
-
- // The primary internal data structure used to organize and store the
- // mapping between target render tree node and animation list.
- // In many cases there are not many active animations, and so we use a
- // base::SmallMap for this. std::map was found to be more performant than
- // base::hash_map, so it is used as the fallback map.
- typedef base::SmallMap<
- std::map<Node*, scoped_refptr<AnimationListBase> >, 4> InternalMap;
- InternalMap node_animation_map_;
- std::vector<scoped_refptr<Node> > node_refs_;
-
- friend class NodeAnimationsMap;
- };
-
- // Since Builder objects are heavy-weight, this constructor allows them to
- // be move constructed into the NodeAnimationsMap object.
- explicit NodeAnimationsMap(Builder::Moved builder) : data_(builder) {}
-
- // Given the passed in current time, this method will apply all contained
- // animations to the passed in render tree, returning a new render tree that
- // has animations applied. Nodes will only be newly created if they are
- // animated or one of their descendants are animated, otherwise the original
- // input node will be used and returned.
- scoped_refptr<Node> Apply(const scoped_refptr<Node>& root,
- base::TimeDelta time_elapsed);
-
- private:
- ~NodeAnimationsMap() {}
-
- // Returns NULL if no animations exist for target node.
- AnimationListBase* GetAnimationsForNode(Node* target) const;
-
- const Builder data_;
-
- class NodeVisitor;
- friend class NodeVisitor;
-
- friend class base::RefCountedThreadSafe<NodeAnimationsMap>;
-};
-
-} // namespace animations
-} // namespace render_tree
-} // namespace cobalt
-
-#endif // COBALT_RENDER_TREE_ANIMATIONS_NODE_ANIMATIONS_MAP_H_
diff --git a/src/cobalt/render_tree/child_iterator.h b/src/cobalt/render_tree/child_iterator.h
new file mode 100644
index 0000000..d5567c5
--- /dev/null
+++ b/src/cobalt/render_tree/child_iterator.h
@@ -0,0 +1,226 @@
+/*
+ * Copyright 2016 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.
+ */
+
+#ifndef COBALT_RENDER_TREE_CHILD_ITERATOR_H_
+#define COBALT_RENDER_TREE_CHILD_ITERATOR_H_
+
+#include "cobalt/render_tree/composition_node.h"
+#include "cobalt/render_tree/filter_node.h"
+#include "cobalt/render_tree/image_node.h"
+#include "cobalt/render_tree/matrix_transform_node.h"
+#include "cobalt/render_tree/node.h"
+#include "cobalt/render_tree/punch_through_video_node.h"
+#include "cobalt/render_tree/rect_node.h"
+#include "cobalt/render_tree/rect_shadow_node.h"
+#include "cobalt/render_tree/text_node.h"
+
+namespace cobalt {
+namespace render_tree {
+
+class ImageNode;
+class PunchThroughVideoNode;
+class RectNode;
+class RectShadowNode;
+class TextNode;
+
+// The ChildIterator template provides a way to iterate over the children of
+// a node without concern for what type of node it is (though since it is a
+// template, the compiler must know the type). Thus, render_tree::NodeVisitor
+// subclasses can forward visits to a ChildIterator if they want to traverse
+// the tree without writing traversal code for specific render tree node types.
+// Additionally, ReplaceCurrent() can be used to modify the list of children
+// at a given node, allowing render tree modifications to be made by code that
+// does not care about what type of render tree nodes it is dealing with.
+// Note that child-related methods like GetCurrent(), Next(), and
+// ReplaceCurrent() are only enabled for nodes that have children. This can
+// be checked via |ChildIterator<T>::has_children|.
+//
+// Example usage:
+//
+// void Visit(CompositionNode* node) { VisitNode(node); }
+// void Visit(ImageNode* node) { VisitNode(node); }
+// ...
+//
+// template <typename T>
+// typename base::enable_if<!ChildIterator<T>::has_children>::type
+// VisitNode(T* node) {
+// ProcessNode();
+// }
+//
+// template <typename T>
+// typename base::enable_if<ChildIterator<T>::has_children>::type VisitNode(
+// T* node) {
+// ProcessNode();
+//
+// // Visit children
+// ChildIterator<T> child_iterator(node);
+// while (Node* child = child_iterator.GetCurrent()) {
+// Visit(child);
+// child_iterator.Next();
+// }
+// }
+//
+// void ProcessNode(Node* node) {
+// // Called on every node
+// ...
+// }
+//
+
+template <typename T, typename = void>
+class ChildIterator {
+ public:
+ // This default class is used for all nodes that have no children.
+ static const bool has_children = false;
+};
+
+enum ChildIteratorDirection {
+ // Decides whether we start at the first or last child.
+ kChildIteratorDirectionForwards,
+ kChildIteratorDirectionBackwards,
+};
+
+// CompositionNodes may have multiple children, so we setup ChildIterator
+// to iterate through each of them.
+template <>
+class ChildIterator<CompositionNode> {
+ public:
+ static const bool has_children = true;
+
+ explicit ChildIterator(
+ CompositionNode* composition,
+ ChildIteratorDirection direction = kChildIteratorDirectionForwards)
+ : composition_node_(composition),
+ children_(composition_node_->data().children()),
+ child_number_(0),
+ direction_(direction) {}
+
+ Node* GetCurrent() const {
+ return done() ? NULL : children_[child_index()].get();
+ }
+ void Next() { ++child_number_; }
+
+ void ReplaceCurrent(const scoped_refptr<Node>& new_child) {
+ DCHECK(!done());
+ if (!modified_children_builder_) {
+ // If we haven't replaced any children yet, we start by constructing a new
+ // modifiable version of this CompositionNode's data so that we can
+ // modify its children.
+ modified_children_builder_ = composition_node_->data();
+ }
+ // Update the modified children list with the newly replaced child.
+ *modified_children_builder_->GetChild(static_cast<int>(child_index())) =
+ new_child;
+ }
+ CompositionNode::Builder::Moved TakeReplacedChildrenBuilder() {
+ return modified_children_builder_->Pass();
+ }
+
+ private:
+ size_t child_index() const {
+ DCHECK(!done());
+ return direction_ == kChildIteratorDirectionForwards
+ ? child_number_
+ : children_.size() - child_number_ - 1;
+ }
+ bool done() const { return child_number_ >= children_.size(); }
+
+ // The node whose children we are iterating through.
+ CompositionNode* composition_node_;
+ // A quick reference to the node's children.
+ const CompositionNode::Children& children_;
+ // The current child index we are at with our iteration.
+ size_t child_number_;
+
+ ChildIteratorDirection direction_;
+
+ // The builder to use if we are modifying the children. If constructed, it
+ // starts as a copy of the origin CompositionNode's data.
+ base::optional<CompositionNode::Builder> modified_children_builder_;
+};
+
+// FilterNodes can have up to 1 child.
+template <>
+class ChildIterator<FilterNode> {
+ public:
+ static const bool has_children = true;
+
+ explicit ChildIterator(
+ FilterNode* filter,
+ ChildIteratorDirection direction = kChildIteratorDirectionForwards)
+ : filter_node_(filter), source_(filter->data().source.get()) {
+ UNREFERENCED_PARAMETER(direction);
+ }
+
+ Node* GetCurrent() const { return source_; }
+ void Next() { source_ = NULL; }
+
+ void ReplaceCurrent(const scoped_refptr<Node>& new_child) {
+ DCHECK(GetCurrent());
+ if (!modified_children_builder_) {
+ modified_children_builder_ = filter_node_->data();
+ }
+ modified_children_builder_->source = new_child;
+ }
+ FilterNode::Builder TakeReplacedChildrenBuilder() {
+ return *modified_children_builder_;
+ }
+
+ private:
+ FilterNode* filter_node_;
+ Node* source_;
+
+ base::optional<FilterNode::Builder> modified_children_builder_;
+};
+
+// MatrixTransformNodes can have up to 1 child.
+template <>
+class ChildIterator<MatrixTransformNode> {
+ public:
+ static const bool has_children = true;
+
+ explicit ChildIterator(
+ MatrixTransformNode* matrix_transform,
+ ChildIteratorDirection direction = kChildIteratorDirectionForwards)
+ : matrix_transform_node_(matrix_transform),
+ source_(matrix_transform->data().source.get()) {
+ UNREFERENCED_PARAMETER(direction);
+ }
+
+ Node* GetCurrent() const { return source_; }
+ void Next() { source_ = NULL; }
+
+ void ReplaceCurrent(const scoped_refptr<Node>& new_child) {
+ DCHECK(GetCurrent());
+ if (!modified_children_builder_) {
+ modified_children_builder_ = matrix_transform_node_->data();
+ }
+ modified_children_builder_->source = new_child;
+ }
+ MatrixTransformNode::Builder TakeReplacedChildrenBuilder() {
+ return *modified_children_builder_;
+ }
+
+ private:
+ MatrixTransformNode* matrix_transform_node_;
+ Node* source_;
+
+ base::optional<MatrixTransformNode::Builder> modified_children_builder_;
+};
+
+} // namespace render_tree
+} // namespace cobalt
+
+#endif // COBALT_RENDER_TREE_CHILD_ITERATOR_H_
diff --git a/src/cobalt/render_tree/dump_render_tree_to_string.cc b/src/cobalt/render_tree/dump_render_tree_to_string.cc
index adee88e..6fdc38e 100644
--- a/src/cobalt/render_tree/dump_render_tree_to_string.cc
+++ b/src/cobalt/render_tree/dump_render_tree_to_string.cc
@@ -31,6 +31,10 @@
namespace cobalt {
namespace render_tree {
+namespace animations {
+class AnimateNode;
+} // namespace animations
+
namespace {
// A render tree visitor that accumulates node dumps to text within a
@@ -39,6 +43,7 @@
public:
DebugTreePrinter() : indent_(0) {}
+ void Visit(animations::AnimateNode* /* animate */) OVERRIDE { NOTREACHED(); }
void Visit(CompositionNode* composition) OVERRIDE;
void Visit(FilterNode* text) OVERRIDE;
void Visit(ImageNode* image) OVERRIDE;
diff --git a/src/cobalt/render_tree/node_visitor.h b/src/cobalt/render_tree/node_visitor.h
index 73b9c21..de6c026 100644
--- a/src/cobalt/render_tree/node_visitor.h
+++ b/src/cobalt/render_tree/node_visitor.h
@@ -29,11 +29,16 @@
class RectShadowNode;
class TextNode;
+namespace animations {
+class AnimateNode;
+} // namespace animations
+
// Type-safe branching on a class hierarchy of render tree nodes,
// implemented after a classical GoF pattern (see
// http://en.wikipedia.org/wiki/Visitor_pattern#Java_example).
class NodeVisitor {
public:
+ virtual void Visit(animations::AnimateNode* animate) = 0;
virtual void Visit(CompositionNode* composition) = 0;
virtual void Visit(FilterNode* text) = 0;
virtual void Visit(ImageNode* image) = 0;
diff --git a/src/cobalt/render_tree/node_visitor_test.cc b/src/cobalt/render_tree/node_visitor_test.cc
index 502a749..7a24cc4 100644
--- a/src/cobalt/render_tree/node_visitor_test.cc
+++ b/src/cobalt/render_tree/node_visitor_test.cc
@@ -20,6 +20,7 @@
#include "cobalt/math/rect_f.h"
#include "cobalt/math/size.h"
+#include "cobalt/render_tree/animations/animate_node.h"
#include "cobalt/render_tree/composition_node.h"
#include "cobalt/render_tree/filter_node.h"
#include "cobalt/render_tree/font.h"
@@ -33,6 +34,7 @@
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
+using cobalt::render_tree::animations::AnimateNode;
using cobalt::render_tree::Brush;
using cobalt::render_tree::BrushVisitor;
using cobalt::render_tree::ColorRGBA;
@@ -53,6 +55,7 @@
class MockNodeVisitor : public NodeVisitor {
public:
+ MOCK_METHOD1(Visit, void(AnimateNode* animate));
MOCK_METHOD1(Visit, void(CompositionNode* composition));
MOCK_METHOD1(Visit, void(FilterNode* image));
MOCK_METHOD1(Visit, void(ImageNode* image));
@@ -99,6 +102,15 @@
} // namespace
+TEST(NodeVisitorTest, VisitsAnimate) {
+ scoped_refptr<DummyImage> dummy_image = make_scoped_refptr(new DummyImage());
+ scoped_refptr<ImageNode> dummy_image_node(new ImageNode(dummy_image));
+ scoped_refptr<AnimateNode> animate_node(new AnimateNode(dummy_image_node));
+ MockNodeVisitor mock_visitor;
+ EXPECT_CALL(mock_visitor, Visit(animate_node.get()));
+ animate_node->Accept(&mock_visitor);
+}
+
TEST(NodeVisitorTest, VisitsImage) {
scoped_refptr<DummyImage> image = make_scoped_refptr(new DummyImage());
scoped_refptr<ImageNode> image_node(new ImageNode(image));
diff --git a/src/cobalt/render_tree/render_tree.gyp b/src/cobalt/render_tree/render_tree.gyp
index 5af25ff..6e7c6a7 100644
--- a/src/cobalt/render_tree/render_tree.gyp
+++ b/src/cobalt/render_tree/render_tree.gyp
@@ -30,6 +30,7 @@
'brush.cc',
'brush.h',
'brush_visitor.h',
+ 'child_iterator.h',
'color_rgba.h',
'composition_node.cc',
'composition_node.h',
@@ -73,8 +74,8 @@
'target_name': 'animations',
'type': 'static_library',
'sources': [
- 'animations/node_animations_map.cc',
- 'animations/node_animations_map.h',
+ 'animations/animate_node.cc',
+ 'animations/animate_node.h',
],
'dependencies': [
'render_tree',
@@ -86,7 +87,7 @@
'target_name': 'render_tree_test',
'type': '<(gtest_target_type)',
'sources': [
- 'animations/node_animations_map_test.cc',
+ 'animations/animate_node_test.cc',
'brush_visitor_test.cc',
'color_rgba_test.cc',
'node_visitor_test.cc',
diff --git a/src/cobalt/renderer/animations_test.cc b/src/cobalt/renderer/animations_test.cc
index 8c488a5..033a78f 100644
--- a/src/cobalt/renderer/animations_test.cc
+++ b/src/cobalt/renderer/animations_test.cc
@@ -16,6 +16,7 @@
#include "base/synchronization/waitable_event.h"
#include "base/threading/simple_thread.h"
+#include "cobalt/render_tree/animations/animate_node.h"
#include "cobalt/render_tree/image.h"
#include "cobalt/render_tree/image_node.h"
#include "cobalt/render_tree/resource_provider.h"
@@ -29,10 +30,10 @@
#include "testing/gtest/include/gtest/gtest.h"
+using cobalt::render_tree::animations::AnimateNode;
using cobalt::render_tree::Image;
using cobalt::render_tree::ImageNode;
using cobalt::render_tree::ResourceProvider;
-using cobalt::render_tree::animations::NodeAnimationsMap;
namespace cobalt {
namespace renderer {
@@ -179,7 +180,7 @@
// Animate the ImageNode and pass in our callback function to be executed
// upon render_tree animation.
- NodeAnimationsMap::Builder animations;
+ AnimateNode::Builder animations;
bool first_animate = true;
animations.Add(test_node,
base::Bind(&AnimateImageNode, &animate_has_started,
@@ -194,9 +195,8 @@
// Submit the render tree and animation to the rendering pipeline for
// rasterization (and the execution of our animation callback).
- pipeline.Submit(Submission(
- test_node, new NodeAnimationsMap(animations.Pass()),
- base::Time::Now() - base::Time::UnixEpoch()));
+ pipeline.Submit(Submission(new AnimateNode(animations, test_node),
+ base::Time::Now() - base::Time::UnixEpoch()));
// Wait for all events that we have planned to occur.
animate_has_started.Wait();
diff --git a/src/cobalt/renderer/pipeline.cc b/src/cobalt/renderer/pipeline.cc
index 66ea9a2..a5f38e7 100644
--- a/src/cobalt/renderer/pipeline.cc
+++ b/src/cobalt/renderer/pipeline.cc
@@ -22,10 +22,11 @@
#include "base/file_util.h"
#include "base/path_service.h"
#include "cobalt/base/cobalt_paths.h"
+#include "cobalt/base/polymorphic_downcast.h"
#include "cobalt/render_tree/dump_render_tree_to_string.h"
using cobalt::render_tree::Node;
-using cobalt::render_tree::animations::NodeAnimationsMap;
+using cobalt::render_tree::animations::AnimateNode;
namespace cobalt {
namespace renderer {
@@ -134,10 +135,11 @@
void Pipeline::Submit(const Submission& render_tree_submission) {
TRACE_EVENT0("cobalt::renderer", "Pipeline::Submit()");
+
// Execute the actual set of the new render tree on the rasterizer tree.
rasterizer_thread_.message_loop()->PostTask(
FROM_HERE, base::Bind(&Pipeline::SetNewRenderTree, base::Unretained(this),
- render_tree_submission));
+ CollectAnimations(render_tree_submission)));
}
void Pipeline::Clear() {
@@ -160,7 +162,7 @@
rasterizer_thread_.message_loop()->PostTask(
FROM_HERE,
base::Bind(&Pipeline::RasterizeToRGBAPixels, base::Unretained(this),
- render_tree_submission, complete));
+ CollectAnimations(render_tree_submission), complete));
return;
}
// Create a new target that is the same dimensions as the display target.
@@ -231,8 +233,11 @@
TRACE_EVENT0("cobalt::renderer",
"Pipeline::RasterizeSubmissionToRenderTarget()");
// Animate the render tree using the submitted animations.
- scoped_refptr<Node> animated_render_tree = submission.animations->Apply(
- submission.render_tree, submission.time_offset);
+ render_tree::animations::AnimateNode* animate_node =
+ base::polymorphic_downcast<render_tree::animations::AnimateNode*>(
+ submission.render_tree.get());
+ scoped_refptr<Node> animated_render_tree =
+ animate_node->Apply(submission.time_offset);
// Rasterize the animated render tree.
rasterizer_->Submit(animated_render_tree, render_target);
@@ -311,8 +316,11 @@
Submission submission =
submission_queue_->GetCurrentSubmission(base::TimeTicks::Now());
- scoped_refptr<Node> animated_render_tree = submission.animations->Apply(
- submission.render_tree, submission.time_offset);
+ render_tree::animations::AnimateNode* animate_node =
+ base::polymorphic_downcast<render_tree::animations::AnimateNode*>(
+ submission.render_tree.get());
+ scoped_refptr<Node> animated_render_tree =
+ animate_node->Apply(submission.time_offset);
std::string tree_dump =
render_tree::DumpRenderTreeToString(animated_render_tree);
@@ -330,5 +338,16 @@
}
#endif // #if defined(ENABLE_DEBUG_CONSOLE)
+Submission Pipeline::CollectAnimations(
+ const Submission& render_tree_submission) {
+ // Constructing an AnimateNode will result in the tree being traversed to
+ // collect all sub-AnimateNodes into the new one, in order to maintain the
+ // invariant that a sub-tree of an AnimateNode has no AnimateNodes.
+ Submission collected_submission = render_tree_submission;
+ collected_submission.render_tree = new render_tree::animations::AnimateNode(
+ render_tree_submission.render_tree);
+ return collected_submission;
+}
+
} // namespace renderer
} // namespace cobalt
diff --git a/src/cobalt/renderer/pipeline.h b/src/cobalt/renderer/pipeline.h
index 98f3f1c..ad05b29 100644
--- a/src/cobalt/renderer/pipeline.h
+++ b/src/cobalt/renderer/pipeline.h
@@ -27,7 +27,7 @@
#include "base/threading/thread_checker.h"
#include "base/timer.h"
#include "cobalt/base/c_val_time_interval_timer.h"
-#include "cobalt/render_tree/animations/node_animations_map.h"
+#include "cobalt/render_tree/animations/animate_node.h"
#include "cobalt/render_tree/node.h"
#include "cobalt/renderer/backend/graphics_context.h"
#include "cobalt/renderer/rasterizer/rasterizer.h"
@@ -125,6 +125,13 @@
void OnDumpCurrentRenderTree(const std::string&);
#endif // defined(ENABLE_DEBUG_CONSOLE)
+ // Render trees may contain a number of AnimateNodes (or none). In order
+ // to optimize for applying the animations on the rasterizer thread, this
+ // function searches the tree for AnimateNodes and collects all of their
+ // information into a single AnimateNode at the root of the returned
+ // render tree.
+ Submission CollectAnimations(const Submission& render_tree_submission);
+
base::WaitableEvent rasterizer_created_event_;
// The render_target that all submitted render trees will be rasterized to.
diff --git a/src/cobalt/renderer/rasterizer/benchmark.cc b/src/cobalt/renderer/rasterizer/benchmark.cc
index aefb362..097d0bf 100644
--- a/src/cobalt/renderer/rasterizer/benchmark.cc
+++ b/src/cobalt/renderer/rasterizer/benchmark.cc
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+#include "cobalt/base/polymorphic_downcast.h"
#include "cobalt/math/size.h"
#include "cobalt/renderer/backend/default_graphics_system.h"
#include "cobalt/renderer/backend/graphics_context.h"
@@ -28,19 +29,20 @@
using cobalt::math::Size;
using cobalt::math::SizeF;
using cobalt::render_tree::AlphaFormat;
+using cobalt::render_tree::animations::AnimateNode;
using cobalt::render_tree::ImageData;
+using cobalt::render_tree::Node;
using cobalt::render_tree::PixelFormat;
using cobalt::render_tree::ResourceProvider;
-using cobalt::renderer::rasterizer::Rasterizer;
-using cobalt::renderer::RendererModule;
using cobalt::renderer::backend::Display;
using cobalt::renderer::backend::GraphicsContext;
using cobalt::renderer::backend::GraphicsSystem;
using cobalt::renderer::backend::RenderTarget;
using cobalt::renderer::backend::SurfaceInfo;
+using cobalt::renderer::rasterizer::Rasterizer;
+using cobalt::renderer::RendererModule;
using cobalt::renderer::test::scenes::AddBlankBackgroundToScene;
using cobalt::renderer::test::scenes::CreateAllScenesCombinedScene;
-using cobalt::renderer::test::scenes::RenderTreeWithAnimations;
using cobalt::system_window::SystemWindow;
namespace {
@@ -63,7 +65,7 @@
kOutputSurfaceTypeOffscreen,
};
-typedef base::Callback<RenderTreeWithAnimations(
+typedef base::Callback<scoped_refptr<Node>(
ResourceProvider*, const SizeF&, base::TimeDelta)> SceneCreateFunction;
// RunRenderTreeSceneBenchmark serves as a framework for render tree scene
@@ -105,15 +107,16 @@
DLOG(FATAL) << "Unknown output surface type.";
}
- RenderTreeWithAnimations scene =
+ scoped_refptr<Node> scene =
scene_create_function.Run(rasterizer->GetResourceProvider(),
test_surface->GetSize(), base::TimeDelta());
const int kRenderIterationCount = 100;
const float kFixedTimeStepInSecondsPerFrame = 0.016f;
for (int i = 0; i < kRenderIterationCount; ++i) {
- scoped_refptr<cobalt::render_tree::Node> animated = scene.animations->Apply(
- scene.render_tree,
+ AnimateNode* animate_node =
+ base::polymorphic_downcast<AnimateNode*>(scene.get());
+ scoped_refptr<Node> animated = animate_node->Apply(
base::TimeDelta::FromSecondsD(i * kFixedTimeStepInSecondsPerFrame));
// Submit the render tree to be rendered.
@@ -133,7 +136,7 @@
#define RENDER_TREE_BUILDER_BENCHMARK(test_name) \
TRACE_EVENT_BENCHMARK5( \
test_name, "BuildRenderTree", cobalt::trace_event::IN_SCOPE_DURATION, \
- "NodeAnimationsMap::Apply()", cobalt::trace_event::IN_SCOPE_DURATION, \
+ "AnimateNode::Apply()", cobalt::trace_event::IN_SCOPE_DURATION, \
"Rasterizer::Submit()", cobalt::trace_event::FLOW_DURATION, \
"Rasterizer::Submit()", cobalt::trace_event::TIME_BETWEEN_EVENT_STARTS, \
"VisitRenderTree", cobalt::trace_event::IN_SCOPE_DURATION)
diff --git a/src/cobalt/renderer/rasterizer/blitter/hardware_rasterizer.cc b/src/cobalt/renderer/rasterizer/blitter/hardware_rasterizer.cc
index 2f73a29..2868926 100644
--- a/src/cobalt/renderer/rasterizer/blitter/hardware_rasterizer.cc
+++ b/src/cobalt/renderer/rasterizer/blitter/hardware_rasterizer.cc
@@ -38,6 +38,7 @@
class HardwareRasterizer::Impl {
public:
explicit Impl(backend::GraphicsContext* graphics_context,
+ int scratch_surface_size_in_bytes,
int surface_cache_size_in_bytes);
~Impl();
@@ -57,16 +58,21 @@
int64 submit_count_;
+ ScratchSurfaceCache scratch_surface_cache_;
base::optional<SurfaceCacheDelegate> surface_cache_delegate_;
base::optional<common::SurfaceCache> surface_cache_;
};
HardwareRasterizer::Impl::Impl(backend::GraphicsContext* graphics_context,
+ int scratch_surface_size_in_bytes,
int surface_cache_size_in_bytes)
: context_(base::polymorphic_downcast<backend::GraphicsContextBlitter*>(
graphics_context)),
software_rasterizer_(0),
- submit_count_(0) {
+ submit_count_(0),
+ scratch_surface_cache_(context_->GetSbBlitterDevice(),
+ context_->GetSbBlitterContext(),
+ scratch_surface_size_in_bytes) {
resource_provider_ = scoped_ptr<render_tree::ResourceProvider>(
new ResourceProvider(context_->GetSbBlitterDevice(),
software_rasterizer_.GetResourceProvider()));
@@ -126,7 +132,7 @@
RenderState(render_target_blitter->GetSbRenderTarget(), Transform(),
BoundsStack(context_->GetSbBlitterContext(),
math::Rect(render_target_blitter->GetSize()))),
- &software_rasterizer_,
+ &software_rasterizer_, &scratch_surface_cache_,
surface_cache_delegate_ ? &surface_cache_delegate_.value() : NULL,
surface_cache_ ? &surface_cache_.value() : NULL);
render_tree->Accept(&visitor);
@@ -144,8 +150,10 @@
}
HardwareRasterizer::HardwareRasterizer(
- backend::GraphicsContext* graphics_context, int surface_cache_size_in_bytes)
- : impl_(new Impl(graphics_context, surface_cache_size_in_bytes)) {}
+ backend::GraphicsContext* graphics_context,
+ int scratch_surface_size_in_bytes, int surface_cache_size_in_bytes)
+ : impl_(new Impl(graphics_context, scratch_surface_size_in_bytes,
+ surface_cache_size_in_bytes)) {}
HardwareRasterizer::~HardwareRasterizer() {}
diff --git a/src/cobalt/renderer/rasterizer/blitter/hardware_rasterizer.h b/src/cobalt/renderer/rasterizer/blitter/hardware_rasterizer.h
index 7562d32..abf4d4e 100644
--- a/src/cobalt/renderer/rasterizer/blitter/hardware_rasterizer.h
+++ b/src/cobalt/renderer/rasterizer/blitter/hardware_rasterizer.h
@@ -21,6 +21,7 @@
#include "cobalt/render_tree/resource_provider.h"
#include "cobalt/renderer/backend/graphics_context.h"
#include "cobalt/renderer/backend/render_target.h"
+#include "cobalt/renderer/rasterizer/blitter/scratch_surface_cache.h"
#include "cobalt/renderer/rasterizer/rasterizer.h"
#if SB_HAS(BLITTER)
@@ -37,6 +38,7 @@
class HardwareRasterizer : public Rasterizer {
public:
explicit HardwareRasterizer(backend::GraphicsContext* graphics_context,
+ int scratch_surface_size_in_bytes,
int surface_cache_size_in_bytes);
virtual ~HardwareRasterizer();
diff --git a/src/cobalt/renderer/rasterizer/blitter/rasterizer.gyp b/src/cobalt/renderer/rasterizer/blitter/rasterizer.gyp
index 0f7f474..8c75fd1 100644
--- a/src/cobalt/renderer/rasterizer/blitter/rasterizer.gyp
+++ b/src/cobalt/renderer/rasterizer/blitter/rasterizer.gyp
@@ -45,6 +45,7 @@
'render_tree_blitter_conversions.cc',
'render_tree_node_visitor.cc',
'resource_provider.cc',
+ 'scratch_surface_cache.cc',
'surface_cache_delegate.cc',
],
diff --git a/src/cobalt/renderer/rasterizer/blitter/render_tree_node_visitor.cc b/src/cobalt/renderer/rasterizer/blitter/render_tree_node_visitor.cc
index 9af227b..3f37aeb 100644
--- a/src/cobalt/renderer/rasterizer/blitter/render_tree_node_visitor.cc
+++ b/src/cobalt/renderer/rasterizer/blitter/render_tree_node_visitor.cc
@@ -54,12 +54,14 @@
SbBlitterDevice device, SbBlitterContext context,
const RenderState& render_state,
skia::SoftwareRasterizer* software_rasterizer,
+ ScratchSurfaceCache* scratch_surface_cache,
SurfaceCacheDelegate* surface_cache_delegate,
common::SurfaceCache* surface_cache)
: software_rasterizer_(software_rasterizer),
device_(device),
context_(context),
render_state_(render_state),
+ scratch_surface_cache_(scratch_surface_cache),
surface_cache_delegate_(surface_cache_delegate),
surface_cache_(surface_cache) {
DCHECK_EQ(surface_cache_delegate_ == NULL, surface_cache_ == NULL);
@@ -135,16 +137,16 @@
// Render our source subtree to an offscreen surface, and then we will
// re-render it to our main render target with an alpha value applied to it.
- OffscreenRender offscreen_render = RenderToOffscreenSurface(source);
- if (!SbBlitterIsSurfaceValid(offscreen_render.surface)) {
+ scoped_ptr<OffscreenRender> offscreen_render =
+ RenderToOffscreenSurface(source);
+ if (!offscreen_render) {
// This can happen if the output area of the source node is 0, in which
// case we're trivially done.
return;
}
- SbBlitterSurfaceInfo offscreen_surface_info;
- CHECK(SbBlitterGetSurfaceInfo(offscreen_render.surface,
- &offscreen_surface_info));
+ SbBlitterSurface offscreen_surface =
+ offscreen_render->scratch_surface->GetSurface();
// Now blit our offscreen surface to our main render target with opacity
// applied.
@@ -154,15 +156,10 @@
context_,
SbBlitterColorFromRGBA(255, 255, 255, static_cast<int>(255 * opacity)));
SbBlitterBlitRectToRect(
- context_, offscreen_render.surface,
- SbBlitterMakeRect(0, 0, offscreen_surface_info.width,
- offscreen_surface_info.height),
- SbBlitterMakeRect(
- offscreen_render.position.x(), offscreen_render.position.y(),
- offscreen_surface_info.width, offscreen_surface_info.height));
-
- // Destroy our temporary offscreeen surface now that we are done with it.
- SbBlitterDestroySurface(offscreen_render.surface);
+ context_, offscreen_surface,
+ SbBlitterMakeRect(0, 0, offscreen_render->destination_rect.width(),
+ offscreen_render->destination_rect.height()),
+ RectFToBlitterRect(offscreen_render->destination_rect));
}
}
@@ -456,7 +453,7 @@
SbBlitterDestroySurface(surface);
}
-RenderTreeNodeVisitor::OffscreenRender
+scoped_ptr<RenderTreeNodeVisitor::OffscreenRender>
RenderTreeNodeVisitor::RenderToOffscreenSurface(render_tree::Node* node) {
common::OffscreenRenderCoordinateMapping coord_mapping =
common::GetOffscreenRenderCoordinateMapping(
@@ -464,9 +461,7 @@
render_state_.bounds_stack.Top());
if (coord_mapping.output_bounds.IsEmpty()) {
// There's nothing to render if the bounds are 0.
- OffscreenRender ret;
- ret.surface = kSbBlitterInvalidSurface;
- return ret;
+ return scoped_ptr<OffscreenRender>();
}
DCHECK_GE(0.001f, std::abs(1.0f -
render_state_.transform.scale().x() *
@@ -475,28 +470,22 @@
render_state_.transform.scale().y() *
coord_mapping.output_post_scale.y()));
- SbBlitterSurface surface = SbBlitterCreateRenderTargetSurface(
- device_, coord_mapping.output_bounds.width(),
- coord_mapping.output_bounds.height(), kSbBlitterSurfaceFormatRGBA8);
+ scoped_ptr<CachedScratchSurface> scratch_surface(new CachedScratchSurface(
+ scratch_surface_cache_, coord_mapping.output_bounds.size()));
+ SbBlitterSurface surface = scratch_surface->GetSurface();
SbBlitterRenderTarget render_target =
SbBlitterGetRenderTargetFromSurface(surface);
SbBlitterSetRenderTarget(context_, render_target);
- // Clear the background to fully transparent before we begin rendering the
- // subtree.
- SbBlitterSetBlending(context_, false);
- SbBlitterSetColor(context_, SbBlitterColorFromRGBA(0, 0, 0, 0));
- SbBlitterFillRect(
- context_, RectToBlitterRect(Rect(coord_mapping.output_bounds.size())));
-
// Render to the sub-surface.
RenderTreeNodeVisitor sub_visitor(
device_, context_,
RenderState(
render_target, Transform(coord_mapping.sub_render_transform),
BoundsStack(context_, Rect(coord_mapping.output_bounds.size()))),
- software_rasterizer_, surface_cache_delegate_, surface_cache_);
+ software_rasterizer_, scratch_surface_cache_, surface_cache_delegate_,
+ surface_cache_);
node->Accept(&sub_visitor);
// Restore our original render target.
@@ -509,11 +498,12 @@
coord_mapping.output_pre_translate +
render_state_.transform.translate();
- OffscreenRender ret;
- ret.position.SetPoint(output_point.x(), output_point.y());
- ret.surface = surface;
+ scoped_ptr<OffscreenRender> ret(new OffscreenRender());
+ ret->destination_rect =
+ math::RectF(output_point, coord_mapping.output_bounds.size());
+ ret->scratch_surface = scratch_surface.Pass();
- return ret;
+ return ret.Pass();
}
} // namespace blitter
diff --git a/src/cobalt/renderer/rasterizer/blitter/render_tree_node_visitor.h b/src/cobalt/renderer/rasterizer/blitter/render_tree_node_visitor.h
index 3370321..4677308 100644
--- a/src/cobalt/renderer/rasterizer/blitter/render_tree_node_visitor.h
+++ b/src/cobalt/renderer/rasterizer/blitter/render_tree_node_visitor.h
@@ -33,6 +33,7 @@
#include "cobalt/render_tree/rect_shadow_node.h"
#include "cobalt/render_tree/text_node.h"
#include "cobalt/renderer/rasterizer/blitter/render_state.h"
+#include "cobalt/renderer/rasterizer/blitter/scratch_surface_cache.h"
#include "cobalt/renderer/rasterizer/blitter/surface_cache_delegate.h"
#include "cobalt/renderer/rasterizer/common/surface_cache.h"
#include "cobalt/renderer/rasterizer/skia/software_rasterizer.h"
@@ -42,6 +43,13 @@
#if SB_HAS(BLITTER)
namespace cobalt {
+
+namespace render_tree {
+namespace animations {
+class AnimateNode;
+} // namespace animations
+} // namespace render_tree
+
namespace renderer {
namespace rasterizer {
namespace blitter {
@@ -55,9 +63,13 @@
RenderTreeNodeVisitor(SbBlitterDevice device, SbBlitterContext context,
const RenderState& render_state,
skia::SoftwareRasterizer* software_rasterizer,
+ ScratchSurfaceCache* scratch_surface_cache,
SurfaceCacheDelegate* surface_cache_delegate,
common::SurfaceCache* surface_cache);
+ void Visit(render_tree::animations::AnimateNode* animate_node) OVERRIDE {
+ NOTREACHED();
+ }
void Visit(render_tree::CompositionNode* composition_node) OVERRIDE;
void Visit(render_tree::FilterNode* filter_node) OVERRIDE;
void Visit(render_tree::ImageNode* image_node) OVERRIDE;
@@ -82,10 +94,10 @@
// Uses a Blitter API sub-visitor to render the provided render tree to a
// offscreen SbBlitterSurface which is then returned.
struct OffscreenRender {
- math::Point position;
- SbBlitterSurface surface;
+ math::RectF destination_rect;
+ scoped_ptr<CachedScratchSurface> scratch_surface;
};
- OffscreenRender RenderToOffscreenSurface(render_tree::Node* node);
+ scoped_ptr<OffscreenRender> RenderToOffscreenSurface(render_tree::Node* node);
// We maintain an instance of a software skia rasterizer which is used to
// render anything that we cannot render via the Blitter API directly.
@@ -97,6 +109,10 @@
// Keeps track of our current render target, transform and clip stack.
RenderState render_state_;
+ // Manager for scratch surfaces used for intermediate rendering during render
+ // tree traversal.
+ ScratchSurfaceCache* scratch_surface_cache_;
+
SurfaceCacheDelegate* surface_cache_delegate_;
common::SurfaceCache* surface_cache_;
base::optional<SurfaceCacheDelegate::ScopedContext>
diff --git a/src/cobalt/renderer/rasterizer/blitter/scratch_surface_cache.cc b/src/cobalt/renderer/rasterizer/blitter/scratch_surface_cache.cc
new file mode 100644
index 0000000..d9b3790
--- /dev/null
+++ b/src/cobalt/renderer/rasterizer/blitter/scratch_surface_cache.cc
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2016 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 "cobalt/renderer/rasterizer/blitter/scratch_surface_cache.h"
+
+#include "cobalt/base/polymorphic_downcast.h"
+#include "starboard/blitter.h"
+
+#if SB_HAS(BLITTER)
+
+namespace cobalt {
+namespace renderer {
+namespace rasterizer {
+namespace blitter {
+
+namespace {
+
+class BlitterSurface : public common::ScratchSurfaceCache::Surface {
+ public:
+ BlitterSurface(SbBlitterSurface surface, const math::Size& size)
+ : surface_(surface), size_(size) {}
+ ~BlitterSurface() OVERRIDE { SbBlitterDestroySurface(surface_); }
+
+ math::Size GetSize() const OVERRIDE { return size_; }
+
+ SbBlitterSurface blitter_surface() { return surface_; }
+
+ private:
+ SbBlitterSurface surface_;
+ math::Size size_;
+};
+} // namespace
+
+ScratchSurfaceCache::ScratchSurfaceCache(SbBlitterDevice device,
+ SbBlitterContext context,
+ int cache_capacity_in_bytes)
+ : delegate_(device, context), cache_(&delegate_, cache_capacity_in_bytes) {}
+
+ScratchSurfaceCache::Delegate::Delegate(SbBlitterDevice device,
+ SbBlitterContext context)
+ : device_(device), context_(context) {}
+
+common::ScratchSurfaceCache::Surface*
+ScratchSurfaceCache::Delegate::CreateSurface(const math::Size& size) {
+ return new BlitterSurface(
+ SbBlitterCreateRenderTargetSurface(device_, size.width(), size.height(),
+ kSbBlitterSurfaceFormatRGBA8),
+ size);
+}
+
+void ScratchSurfaceCache::Delegate::DestroySurface(
+ common::ScratchSurfaceCache::Surface* surface) {
+ delete surface;
+}
+
+void ScratchSurfaceCache::Delegate::PrepareForUse(
+ common::ScratchSurfaceCache::Surface* surface, const math::Size& area) {
+ SbBlitterSurface blitter_surface =
+ base::polymorphic_downcast<BlitterSurface*>(surface)->blitter_surface();
+
+ SbBlitterSetRenderTarget(
+ context_, SbBlitterGetRenderTargetFromSurface(blitter_surface));
+ SbBlitterSetBlending(context_, false);
+ SbBlitterSetColor(context_, SbBlitterColorFromRGBA(0, 0, 0, 0));
+ SbBlitterFillRect(context_,
+ SbBlitterMakeRect(0, 0, area.width(), area.height()));
+}
+
+SbBlitterSurface CachedScratchSurface::GetSurface() {
+ return base::polymorphic_downcast<BlitterSurface*>(
+ common_scratch_surface_.GetSurface())
+ ->blitter_surface();
+}
+
+} // namespace blitter
+} // namespace rasterizer
+} // namespace renderer
+} // namespace cobalt
+
+#endif // SB_HAS(BLITTER)
diff --git a/src/cobalt/renderer/rasterizer/blitter/scratch_surface_cache.h b/src/cobalt/renderer/rasterizer/blitter/scratch_surface_cache.h
new file mode 100644
index 0000000..675a498
--- /dev/null
+++ b/src/cobalt/renderer/rasterizer/blitter/scratch_surface_cache.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2016 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.
+ */
+
+#ifndef COBALT_RENDERER_RASTERIZER_BLITTER_SCRATCH_SURFACE_CACHE_H_
+#define COBALT_RENDERER_RASTERIZER_BLITTER_SCRATCH_SURFACE_CACHE_H_
+
+#include "cobalt/math/size.h"
+#include "cobalt/renderer/rasterizer/common/scratch_surface_cache.h"
+#include "starboard/blitter.h"
+
+#if SB_HAS(BLITTER)
+
+namespace cobalt {
+namespace renderer {
+namespace rasterizer {
+namespace blitter {
+
+// We define a blitter::ScratchSurfaceCache class here that decorates
+// common::ScratchSurfaceCache by customizing it to be Blitter API specific.
+// A Blitter API renderer can use this class to request temporary scratch
+// SbBlitterSurfaces that can be automatically re-used over the course of a
+// frame. CachedScratchSurface objects must be created in order to actually
+// interact with ScratchSurfaceCache.
+class ScratchSurfaceCache {
+ public:
+ // |device| specifies the |device| from which surfaces should be allocated
+ // from and |context| specifies which context to use when draw commands need
+ // to be issued (e.g. to clear a surface so it is ready for use).
+ ScratchSurfaceCache(SbBlitterDevice device, SbBlitterContext context,
+ int cache_capacity_in_bytes);
+
+ private:
+ class Delegate : public common::ScratchSurfaceCache::Delegate {
+ public:
+ Delegate(SbBlitterDevice device, SbBlitterContext context);
+
+ common::ScratchSurfaceCache::Surface* CreateSurface(
+ const math::Size& size) OVERRIDE;
+ void DestroySurface(common::ScratchSurfaceCache::Surface* surface) OVERRIDE;
+ void PrepareForUse(common::ScratchSurfaceCache::Surface* surface,
+ const math::Size& area) OVERRIDE;
+
+ private:
+ SbBlitterDevice device_;
+ SbBlitterContext context_;
+ };
+
+ Delegate delegate_;
+ common::ScratchSurfaceCache cache_;
+
+ friend class CachedScratchSurface;
+};
+
+// This class acts as the interface to ScratchSurfaceCache. It does so by
+// decorating common::CachedScratchSurface and adding methods to obtain
+// a reference to the Blitter API-specific SbBlitterSurface object.
+class CachedScratchSurface {
+ public:
+ CachedScratchSurface(ScratchSurfaceCache* cache, const math::Size& size)
+ : common_scratch_surface_(&cache->cache_, size) {}
+
+ // Returns a pointer to the Blitter surface.
+ SbBlitterSurface GetSurface();
+
+ private:
+ common::CachedScratchSurface common_scratch_surface_;
+};
+
+} // namespace blitter
+} // namespace rasterizer
+} // namespace renderer
+} // namespace cobalt
+
+#endif // SB_HAS(BLITTER)
+
+#endif // COBALT_RENDERER_RASTERIZER_BLITTER_SCRATCH_SURFACE_CACHE_H_
diff --git a/src/cobalt/renderer/rasterizer/common/common.gyp b/src/cobalt/renderer/rasterizer/common/common.gyp
index b03b34a..3db2828 100644
--- a/src/cobalt/renderer/rasterizer/common/common.gyp
+++ b/src/cobalt/renderer/rasterizer/common/common.gyp
@@ -20,8 +20,13 @@
'sources': [
'offscreen_render_coordinate_mapping.cc',
+ 'offscreen_render_coordinate_mapping.h',
+ 'scratch_surface_cache.cc',
+ 'scratch_surface_cache.h',
'streaming_best_fit_line.cc',
+ 'streaming_best_fit_line.h',
'surface_cache.cc',
+ 'surface_cache.h',
],
'dependencies': [
diff --git a/src/cobalt/renderer/rasterizer/common/scratch_surface_cache.cc b/src/cobalt/renderer/rasterizer/common/scratch_surface_cache.cc
new file mode 100644
index 0000000..dac975b
--- /dev/null
+++ b/src/cobalt/renderer/rasterizer/common/scratch_surface_cache.cc
@@ -0,0 +1,180 @@
+/*
+ * Copyright 2016 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 "cobalt/renderer/rasterizer/common/scratch_surface_cache.h"
+
+#include <limits>
+
+#include "base/debug/trace_event.h"
+
+namespace cobalt {
+namespace renderer {
+namespace rasterizer {
+namespace common {
+
+namespace {
+
+// Approximate the memory usage of a given surface size.
+size_t ApproximateSurfaceMemory(const math::Size& size) {
+ // Here we assume that we use 4 bytes per pixel.
+ return size.width() * size.height() * 4;
+}
+
+} // namespace
+
+ScratchSurfaceCache::ScratchSurfaceCache(Delegate* delegate,
+ int cache_capacity_in_bytes)
+ : delegate_(delegate),
+ cache_capacity_in_bytes_(cache_capacity_in_bytes),
+ surface_memory_(0) {}
+
+ScratchSurfaceCache::~ScratchSurfaceCache() {
+ DCHECK(surface_stack_.empty());
+ for (std::vector<Surface*>::iterator iter = unused_surfaces_.begin();
+ iter != unused_surfaces_.end(); ++iter) {
+ delegate_->DestroySurface(*iter);
+ }
+}
+
+ScratchSurfaceCache::Surface* ScratchSurfaceCache::AcquireScratchSurface(
+ const math::Size& size) {
+ TRACE_EVENT2("cobalt::renderer",
+ "ScratchSurfaceCache::AcquireScratchSurface()", "width",
+ size.width(), "height", size.height());
+
+ // First check if we can find a suitable surface in our cache that is at
+ // least the size requested.
+ Surface* surface = FindBestCachedSurface(size);
+
+ // If we didn't have any suitable surfaces in our cache, create a new one.
+ if (!surface) {
+ // Increase our total memory used on surfaces, and then initiate a purge
+ // to reduce memory to below our cache limit, if necessary.
+ surface_memory_ += ApproximateSurfaceMemory(size);
+ Purge();
+
+ // Create the surface.
+ surface = delegate_->CreateSurface(size);
+
+ if (!surface) {
+ // We were unable to allocate a scratch surface, either because we are
+ // low on memory or because the requested surface has large dimensions.
+ // Return null.
+ surface_memory_ -= ApproximateSurfaceMemory(size);
+ return NULL;
+ }
+ }
+
+ DCHECK(surface);
+
+ // Track that we have handed out this surface.
+ surface_stack_.push_back(surface);
+
+ delegate_->PrepareForUse(surface, size);
+
+ return surface;
+}
+
+void ScratchSurfaceCache::ReleaseScratchSurface(Surface* surface) {
+ TRACE_EVENT2("cobalt::renderer",
+ "ScratchSurfaceCache::ReleaseScratchSurface()", "width",
+ surface->GetSize().width(), "height",
+ surface->GetSize().height());
+
+ DCHECK_EQ(surface_stack_.back(), surface);
+ surface_stack_.pop_back();
+
+ // Add this surface to the end (where most recently used surfaces go) of the
+ // unused surfaces list, so that it can be returned by later calls to acquire
+ // a surface.
+ unused_surfaces_.push_back(surface);
+}
+
+namespace {
+
+float GetMatchScoreForSurfaceAndSize(ScratchSurfaceCache::Surface* surface,
+ const math::Size& size) {
+ math::Size surface_size = surface->GetSize();
+
+ // We use the negated sum of the squared differences between the requested
+ // width/height and the surface width/height as the score.
+ // This promotes returning the smallest surface possible that has a similar
+ // ratio.
+ int width_diff = surface_size.width() - size.width();
+ int height_diff = surface_size.height() - size.height();
+
+ return -width_diff * width_diff - height_diff * height_diff;
+}
+
+} // namespace
+
+ScratchSurfaceCache::Surface* ScratchSurfaceCache::FindBestCachedSurface(
+ const math::Size& size) {
+ // Iterate through all cached surfaces to find the one that is the best match
+ // for the given size. The function GetMatchScoreForSurfaceAndSize() is
+ // responsible for assigning a score to a Surface/math::Size pair.
+ float max_surface_score = -std::numeric_limits<float>::infinity();
+ std::vector<Surface*>::iterator max_iter = unused_surfaces_.end();
+ for (std::vector<Surface*>::iterator iter = unused_surfaces_.begin();
+ iter != unused_surfaces_.end(); ++iter) {
+ Surface* current_surface = *iter;
+ math::Size surface_size = current_surface->GetSize();
+ if (surface_size.width() >= size.width() &&
+ surface_size.height() >= size.height()) {
+ float surface_score =
+ GetMatchScoreForSurfaceAndSize(current_surface, size);
+
+ if (surface_score > max_surface_score) {
+ max_surface_score = surface_score;
+ max_iter = iter;
+ }
+ }
+ }
+
+ // If any of the cached unused surfaces had at least the specified
+ // width/height, return the one that had the highest score.
+ if (max_iter != unused_surfaces_.end()) {
+ Surface* surface = *max_iter;
+ // Remove this surface from the list of unused surfaces.
+ unused_surfaces_.erase(max_iter);
+ // Return the cached surface.
+ return surface;
+ } else {
+ // Otherwise return NULL to indicate that we do not have any suitable cached
+ // surfaces.
+ return NULL;
+ }
+}
+
+void ScratchSurfaceCache::Purge() {
+ // Delete surfaces from the front (least recently used) of |unused_surfaces_|
+ // until we have deleted all surfaces or lowered our memory usage to under
+ // |cache_capacity_in_bytes_|.
+ while (!unused_surfaces_.empty() &&
+ surface_memory_ > cache_capacity_in_bytes_) {
+ Surface* to_free = unused_surfaces_.front();
+ math::Size surface_size = to_free->GetSize();
+ surface_memory_ -= ApproximateSurfaceMemory(
+ math::Size(surface_size.width(), surface_size.height()));
+ delegate_->DestroySurface(to_free);
+ unused_surfaces_.erase(unused_surfaces_.begin());
+ }
+}
+
+} // namespace common
+} // namespace rasterizer
+} // namespace renderer
+} // namespace cobalt
diff --git a/src/cobalt/renderer/rasterizer/common/scratch_surface_cache.h b/src/cobalt/renderer/rasterizer/common/scratch_surface_cache.h
new file mode 100644
index 0000000..a482ffc
--- /dev/null
+++ b/src/cobalt/renderer/rasterizer/common/scratch_surface_cache.h
@@ -0,0 +1,130 @@
+/*
+ * Copyright 2016 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.
+ */
+
+#ifndef COBALT_RENDERER_RASTERIZER_COMMON_SCRATCH_SURFACE_CACHE_H_
+#define COBALT_RENDERER_RASTERIZER_COMMON_SCRATCH_SURFACE_CACHE_H_
+
+#include <vector>
+
+#include "base/callback.h"
+#include "base/logging.h"
+#include "cobalt/math/size.h"
+
+namespace cobalt {
+namespace renderer {
+namespace rasterizer {
+namespace common {
+
+// The ScratchSurfaceCache manages a set of platform-specific surface objects
+// that can be used for offscreen rendering (e.g. by a RenderTreeNodeVisitor).
+// In order to acquire surfaces from ScratchSurfaceCache, one should construct
+// a CachedScratchSurface object, from which they can get a pointer to the
+// Surface object.
+// It is unique because it caters to RenderTreeNodeVisitor's scratch
+// surface allocation pattern. In particular, we don't mind handing out very
+// large scratch surfaces when very small surfaces are requested, because
+// typically only one surface is ever needed at a time. When multiple surfaces
+// are necessary, the subsequent ones tend to be smaller than the previous
+// (because rendering is now happening within the previous ones), and so handing
+// out textures in large to small order makes sense.
+class ScratchSurfaceCache {
+ public:
+ class Surface {
+ public:
+ virtual ~Surface() {}
+ virtual math::Size GetSize() const = 0;
+ };
+ class Delegate {
+ public:
+ virtual Surface* CreateSurface(const math::Size& size) = 0;
+ virtual void DestroySurface(Surface* surface) = 0;
+ virtual void PrepareForUse(Surface* surface, const math::Size& area) = 0;
+ };
+
+ ScratchSurfaceCache(Delegate* delegate, int cache_capacity_in_bytes);
+ ~ScratchSurfaceCache();
+
+ private:
+ // Acquire (either via cache lookup or by creation if that fails) a scratch
+ // surface.
+ Surface* AcquireScratchSurface(const math::Size& size);
+ void ReleaseScratchSurface(Surface* surface);
+
+ // Searches through |unused_surfaces_| for one the one that best matches the
+ // requested size, among all those cached surfaces that have at least the
+ // requested size.
+ Surface* FindBestCachedSurface(const math::Size& size);
+
+ // Removes elements from the cache until we are below the cache limit.
+ void Purge();
+
+ // Allocate a new Surface and return it.
+ Surface* CreateScratchSurface(const math::Size& size);
+
+ // Implementation-specific details about how to create/destroy surfaces.
+ Delegate* delegate_;
+
+ // The maximum number of surface bytes that can be stored in the cache.
+ int cache_capacity_in_bytes_;
+
+ // We keep track of all surfaces we've handed out using |surface_stack_|.
+ // This is mostly for debug checks to verify that surfaces returned to us
+ // actually did come from us, and that they are returned in the expected
+ // order.
+ std::vector<Surface*> surface_stack_;
+
+ // |unused_surfaces_| is the heart of the cache, as it stores the surfaces
+ // that are unused but allocated and available to be handed out upon request.
+ // Most recently used surfaces are found at the end of this vector.
+ std::vector<Surface*> unused_surfaces_;
+
+ // Tracks how much total memory we've allocated towards surfaces.
+ size_t surface_memory_;
+
+ friend class CachedScratchSurface;
+};
+
+// The primary interface to ScratchSurfaceCache is through CachedScratchSurface
+// objects. These effectively scope the acquisition of a cached surface, RAII
+// style.
+class CachedScratchSurface {
+ public:
+ CachedScratchSurface(ScratchSurfaceCache* cache, const math::Size& size)
+ : cache_(cache) {
+ surface_ = cache_->AcquireScratchSurface(size);
+ }
+
+ ~CachedScratchSurface() {
+ if (surface_) {
+ cache_->ReleaseScratchSurface(surface_);
+ }
+ }
+
+ // Returns a pointer to the platform-specific surface. The platform can then
+ // downcast to the expected surface type.
+ ScratchSurfaceCache::Surface* GetSurface() { return surface_; }
+
+ private:
+ ScratchSurfaceCache* cache_;
+ ScratchSurfaceCache::Surface* surface_;
+};
+
+} // namespace common
+} // namespace rasterizer
+} // namespace renderer
+} // namespace cobalt
+
+#endif // COBALT_RENDERER_RASTERIZER_COMMON_SCRATCH_SURFACE_CACHE_H_
diff --git a/src/cobalt/renderer/rasterizer/rasterizer_benchmark.cc b/src/cobalt/renderer/rasterizer/rasterizer_benchmark.cc
index 943cb95..ca2cc73 100644
--- a/src/cobalt/renderer/rasterizer/rasterizer_benchmark.cc
+++ b/src/cobalt/renderer/rasterizer/rasterizer_benchmark.cc
@@ -134,14 +134,13 @@
// Setup a quick macro so that we can measure the same events for each
// render tree builder benchmark.
-#define RENDER_TREE_BUILDER_BENCHMARK(test_name)\
-TRACE_EVENT_BENCHMARK5(\
- test_name, \
- "BuildRenderTree", cobalt::trace_event::IN_SCOPE_DURATION, \
- "NodeAnimationsMap::Apply()", cobalt::trace_event::IN_SCOPE_DURATION, \
- "Rasterizer::Submit()", cobalt::trace_event::FLOW_DURATION, \
- "Rasterizer::Submit()", cobalt::trace_event::TIME_BETWEEN_EVENT_STARTS, \
- "VisitRenderTree", cobalt::trace_event::IN_SCOPE_DURATION)
+#define RENDER_TREE_BUILDER_BENCHMARK(test_name) \
+ TRACE_EVENT_BENCHMARK5( \
+ test_name, "BuildRenderTree", cobalt::trace_event::IN_SCOPE_DURATION, \
+ "AnimateNode::Apply()", cobalt::trace_event::IN_SCOPE_DURATION, \
+ "Rasterizer::Submit()", cobalt::trace_event::FLOW_DURATION, \
+ "Rasterizer::Submit()", cobalt::trace_event::TIME_BETWEEN_EVENT_STARTS, \
+ "VisitRenderTree", cobalt::trace_event::IN_SCOPE_DURATION)
// A catch-all test that excercises every different render tree node at the
// same time. This is the same render tree builder used by the renderer
diff --git a/src/cobalt/renderer/rasterizer/skia/render_tree_node_visitor.h b/src/cobalt/renderer/rasterizer/skia/render_tree_node_visitor.h
index 74f4be2..b325107 100644
--- a/src/cobalt/renderer/rasterizer/skia/render_tree_node_visitor.h
+++ b/src/cobalt/renderer/rasterizer/skia/render_tree_node_visitor.h
@@ -33,6 +33,13 @@
#include "third_party/skia/include/core/SkCanvas.h"
namespace cobalt {
+
+namespace render_tree {
+namespace animations {
+class AnimateNode;
+} // namespace animations
+} // namespace render_tree
+
namespace renderer {
namespace rasterizer {
namespace skia {
@@ -68,6 +75,9 @@
SurfaceCacheDelegate* surface_cache_delegate,
common::SurfaceCache* surface_cache, Type visitor_type = kType_Normal);
+ void Visit(render_tree::animations::AnimateNode* animate_node) OVERRIDE {
+ NOTREACHED();
+ }
void Visit(render_tree::CompositionNode* composition_node) OVERRIDE;
void Visit(render_tree::FilterNode* filter_node) OVERRIDE;
void Visit(render_tree::ImageNode* image_node) OVERRIDE;
diff --git a/src/cobalt/renderer/rasterizer/skia/scratch_surface_cache.cc b/src/cobalt/renderer/rasterizer/skia/scratch_surface_cache.cc
index 1b62b9c..409c787 100644
--- a/src/cobalt/renderer/rasterizer/skia/scratch_surface_cache.cc
+++ b/src/cobalt/renderer/rasterizer/skia/scratch_surface_cache.cc
@@ -16,10 +16,7 @@
#include "cobalt/renderer/rasterizer/skia/scratch_surface_cache.h"
-#include <limits>
-
-#include "base/debug/trace_event.h"
-
+#include "cobalt/base/polymorphic_downcast.h"
#include "third_party/skia/include/core/SkCanvas.h"
namespace cobalt {
@@ -29,160 +26,68 @@
namespace {
-// Approximate the memory usage of a given surface size.
-size_t ApproximateSurfaceMemory(const math::Size& size) {
- // Here we assume that we use 4 bytes per pixel.
- return size.width() * size.height() * 4;
-}
+class SkiaSurface : public common::ScratchSurfaceCache::Surface {
+ public:
+ SkiaSurface(SkSurface* surface, const math::Size& size)
+ : surface_(surface), size_(size) {}
+ math::Size GetSize() const OVERRIDE { return size_; }
+
+ SkSurface* sk_surface() { return surface_.get(); }
+
+ private:
+ SkAutoTUnref<SkSurface> surface_;
+ math::Size size_;
+};
} // namespace
ScratchSurfaceCache::ScratchSurfaceCache(
- const CreateSkSurfaceFunction& create_sk_surface_function,
+ CreateSkSurfaceFunction create_sk_surface_function,
int cache_capacity_in_bytes)
- : create_sk_surface_function_(create_sk_surface_function),
- cache_capacity_in_bytes_(cache_capacity_in_bytes),
- surface_memory_(0) {}
+ : delegate_(create_sk_surface_function),
+ cache_(&delegate_, cache_capacity_in_bytes) {}
-ScratchSurfaceCache::~ScratchSurfaceCache() {
- DCHECK(surface_stack_.empty());
- for (std::vector<SkSurface*>::iterator iter = unused_surfaces_.begin();
- iter != unused_surfaces_.end(); ++iter) {
- (*iter)->unref();
- }
+ScratchSurfaceCache::Delegate::Delegate(
+ CreateSkSurfaceFunction create_sk_surface_function)
+ : create_sk_surface_function_(create_sk_surface_function) {}
+
+common::ScratchSurfaceCache::Surface*
+ScratchSurfaceCache::Delegate::CreateSurface(const math::Size& size) {
+ return new SkiaSurface(create_sk_surface_function_.Run(size), size);
}
-SkSurface* ScratchSurfaceCache::AcquireScratchSurface(const math::Size& size) {
- TRACE_EVENT2("cobalt::renderer",
- "ScratchSurfaceCache::AcquireScratchSurface()", "width",
- size.width(), "height", size.height());
+void ScratchSurfaceCache::Delegate::DestroySurface(
+ common::ScratchSurfaceCache::Surface* surface) {
+ delete surface;
+}
- // First check if we can find a suitable surface in our cache that is at
- // least the size requested.
- SkSurface* surface = FindBestCachedSurface(size);
+void ScratchSurfaceCache::Delegate::PrepareForUse(
+ common::ScratchSurfaceCache::Surface* surface, const math::Size& area) {
+ SkSurface* sk_surface =
+ base::polymorphic_downcast<SkiaSurface*>(surface)->sk_surface();
- // If we didn't have any suitable surfaces in our cache, create a new one.
- if (!surface) {
- // Increase our total memory used on surfaces, and then initiate a purge
- // to reduce memory to below our cache limit, if necessary.
- surface_memory_ += ApproximateSurfaceMemory(size);
- Purge();
-
- // Create the surface.
- surface = create_sk_surface_function_.Run(size);
-
- if (!surface) {
- // We were unable to allocate a scratch surface, either because we are
- // low on memory or because the requested surface has large dimensions.
- // Return null.
- surface_memory_ -= ApproximateSurfaceMemory(size);
- return NULL;
- }
- }
-
- DCHECK(surface);
-
- // Track that we have handed out this surface.
- surface_stack_.push_back(surface);
-
- // Reset the surface's canvas settings such as transform matrix and clip.
- SkCanvas* canvas = surface->getCanvas();
+ // Reset the sk_surface's canvas settings such as transform matrix and clip.
+ SkCanvas* canvas = sk_surface->getCanvas();
canvas->restoreToCount(1);
// Setup a save marker on the reset canvas so that we can restore this reset
- // state when re-using the surface.
+ // state when re-using the sk_surface.
canvas->save();
- // Setup a clip rect on the surface to the requested size. This can save
- // us from drawing to pixels outside of the requested size, since the actual
- // surface returned may be larger than the requested size.
- canvas->clipRect(SkRect::MakeWH(size.width(), size.height()),
+ // Setup a clip rect on the sk_surface to the requested area. This can save
+ // us from drawing to pixels outside of the requested area, since the actual
+ // sk_surface returned may be larger than the requested area.
+ canvas->clipRect(SkRect::MakeWH(area.width(), area.height()),
SkRegion::kReplace_Op);
// Clear the draw area to RGBA(0, 0, 0, 0), as expected for a fresh scratch
- // surface, before returning.
+ // sk_surface, before returning.
canvas->drawARGB(0, 0, 0, 0, SkXfermode::kClear_Mode);
-
- return surface;
}
-void ScratchSurfaceCache::ReleaseScratchSurface(SkSurface* surface) {
- TRACE_EVENT2("cobalt::renderer",
- "ScratchSurfaceCache::ReleaseScratchSurface()", "width",
- surface->width(), "height", surface->height());
-
- DCHECK_EQ(surface_stack_.back(), surface);
- surface_stack_.pop_back();
-
- // Add this surface to the end (where most recently used surfaces go) of the
- // unused surfaces list, so that it can be returned by later calls to acquire
- // a surface.
- unused_surfaces_.push_back(surface);
-}
-
-namespace {
-
-float GetMatchScoreForSurfaceAndSize(SkSurface* surface,
- const math::Size& size) {
- // We use the negated sum of the squared differences between the requested
- // width/height and the surface width/height as the score.
- // This promotes returning the smallest surface possible that has a similar
- // ratio.
- int width_diff = surface->width() - size.width();
- int height_diff = surface->height() - size.height();
-
- return -width_diff * width_diff - height_diff * height_diff;
-}
-
-} // namespace
-
-SkSurface* ScratchSurfaceCache::FindBestCachedSurface(const math::Size& size) {
- // Iterate through all cached surfaces to find the one that is the best match
- // for the given size. The function GetMatchScoreForSurfaceAndSize() is
- // responsible for assigning a score to a SkSurface/math::Size pair.
- float max_surface_score = -std::numeric_limits<float>::infinity();
- std::vector<SkSurface*>::iterator max_iter = unused_surfaces_.end();
- for (std::vector<SkSurface*>::iterator iter = unused_surfaces_.begin();
- iter != unused_surfaces_.end(); ++iter) {
- SkSurface* current_surface = *iter;
- if (current_surface->width() >= size.width() &&
- current_surface->height() >= size.height()) {
- float surface_score =
- GetMatchScoreForSurfaceAndSize(current_surface, size);
-
- if (surface_score > max_surface_score) {
- max_surface_score = surface_score;
- max_iter = iter;
- }
- }
- }
-
- // If any of the cached unused surfaces had at least the specified
- // width/height, return the one that had the highest score.
- if (max_iter != unused_surfaces_.end()) {
- SkSurface* surface = *max_iter;
- // Remove this surface from the list of unused surfaces.
- unused_surfaces_.erase(max_iter);
- // Return the cached surface.
- return surface;
- } else {
- // Otherwise return NULL to indicate that we do not have any suitable cached
- // surfaces.
- return NULL;
- }
-}
-
-void ScratchSurfaceCache::Purge() {
- // Delete surfaces from the front (least recently used) of |unused_surfaces_|
- // until we have deleted all surfaces or lowered our memory usage to under
- // |cache_capacity_in_bytes_|.
- while (!unused_surfaces_.empty() &&
- surface_memory_ > cache_capacity_in_bytes_) {
- SkSurface* to_free = unused_surfaces_.front();
- surface_memory_ -= ApproximateSurfaceMemory(
- math::Size(to_free->width(), to_free->height()));
- to_free->unref();
- unused_surfaces_.erase(unused_surfaces_.begin());
- }
+SkSurface* CachedScratchSurface::GetSurface() {
+ return base::polymorphic_downcast<SkiaSurface*>(
+ common_scratch_surface_.GetSurface())
+ ->sk_surface();
}
} // namespace skia
diff --git a/src/cobalt/renderer/rasterizer/skia/scratch_surface_cache.h b/src/cobalt/renderer/rasterizer/skia/scratch_surface_cache.h
index 374cc66..eaf7ea5 100644
--- a/src/cobalt/renderer/rasterizer/skia/scratch_surface_cache.h
+++ b/src/cobalt/renderer/rasterizer/skia/scratch_surface_cache.h
@@ -22,96 +22,52 @@
#include "base/callback.h"
#include "base/logging.h"
#include "cobalt/math/size.h"
+#include "cobalt/renderer/rasterizer/common/scratch_surface_cache.h"
#include "third_party/skia/include/core/SkSurface.h"
-#include "third_party/skia/include/core/SkSurfaceProps.h"
namespace cobalt {
namespace renderer {
namespace rasterizer {
namespace skia {
-// The ScratchSurfaceCache manages a set of Skia SkSurface objects that can
-// be used for offscreen rendering (mainly by SkiaRenderTreeNodeVisitor).
-// In order to acquire surfaces from ScratchSurfaceCache, one should construct
-// a CachedScratchSurface object, from which they can get a pointer to the
-// SkSurface object.
-// It is unique because it caters to SkiaRenderTreeNodeVisitor's scratch
-// surface allocation pattern. In particular, we don't mind handing out very
-// large scratch surfaces when very small surfaces are requested, because
-// typically only one surface is ever needed at a time. When multiple surfaces
-// are necessary, the subsequent ones tend to be smaller than the previous
-// (because rendering is now happening within the previous ones), and so handing
-// out textures in large to small order makes sense.
class ScratchSurfaceCache {
public:
typedef base::Callback<SkSurface*(const math::Size&)> CreateSkSurfaceFunction;
- ScratchSurfaceCache(const CreateSkSurfaceFunction& create_sk_surface_function,
+ ScratchSurfaceCache(CreateSkSurfaceFunction create_sk_surface_function,
int cache_capacity_in_bytes);
- ~ScratchSurfaceCache();
private:
- // Acquire (either via cache lookup or by creation if that fails) a scratch
- // surface.
- SkSurface* AcquireScratchSurface(const math::Size& size);
- void ReleaseScratchSurface(SkSurface* surface);
+ class Delegate : public common::ScratchSurfaceCache::Delegate {
+ public:
+ explicit Delegate(CreateSkSurfaceFunction create_sk_surface_function);
- // Searches through |unused_surfaces_| for one the one that best matches the
- // requested size, among all those cached surfaces that have at least the
- // requested size.
- SkSurface* FindBestCachedSurface(const math::Size& size);
+ common::ScratchSurfaceCache::Surface* CreateSurface(
+ const math::Size& size) OVERRIDE;
+ void DestroySurface(common::ScratchSurfaceCache::Surface* surface) OVERRIDE;
+ void PrepareForUse(common::ScratchSurfaceCache::Surface* surface,
+ const math::Size& area) OVERRIDE;
- // Removes elements from the cache until we are below the cache limit.
- void Purge();
+ private:
+ CreateSkSurfaceFunction create_sk_surface_function_;
+ };
- // Allocate a new SkSurface and return it.
- SkSurface* CreateScratchSurface(const math::Size& size);
-
- // Called to allocate new SkSurfaces.
- CreateSkSurfaceFunction create_sk_surface_function_;
-
- // The maximum number of surface bytes that can be stored in the cache.
- int cache_capacity_in_bytes_;
-
- // We keep track of all surfaces we've handed out using |surface_stack_|.
- // This is mostly for debug checks to verify that surfaces returned to us
- // actually did come from us, and that they are returned in the expected
- // order.
- std::vector<SkSurface*> surface_stack_;
-
- // |unused_surfaces_| is the heart of the cache, as it stores the surfaces
- // that are unused but allocated and available to be handed out upon request.
- // Most recently used surfaces are found at the end of this vector.
- std::vector<SkSurface*> unused_surfaces_;
-
- // Tracks how much total memory we've allocated towards surfaces.
- size_t surface_memory_;
+ Delegate delegate_;
+ common::ScratchSurfaceCache cache_;
friend class CachedScratchSurface;
};
-// The primary interface to ScratchSurfaceCache is through CachedScratchSurface
-// objects. These effectively scope the acquisition of a cached surface, RAII
-// style.
class CachedScratchSurface {
public:
CachedScratchSurface(ScratchSurfaceCache* cache, const math::Size& size)
- : cache_(cache) {
- surface_ = cache_->AcquireScratchSurface(size);
- }
-
- ~CachedScratchSurface() {
- if (surface_) {
- cache_->ReleaseScratchSurface(surface_);
- }
- }
+ : common_scratch_surface_(&cache->cache_, size) {}
// Returns a pointer to the Skia SkSurface.
- SkSurface* GetSurface() { return surface_; }
+ SkSurface* GetSurface();
private:
- ScratchSurfaceCache* cache_;
- SkSurface* surface_;
+ common::CachedScratchSurface common_scratch_surface_;
};
} // namespace skia
diff --git a/src/cobalt/renderer/renderer_module_default_options_starboard.cc b/src/cobalt/renderer/renderer_module_default_options_starboard.cc
index 50a38f0..db5086b 100644
--- a/src/cobalt/renderer/renderer_module_default_options_starboard.cc
+++ b/src/cobalt/renderer/renderer_module_default_options_starboard.cc
@@ -53,7 +53,8 @@
#else
return scoped_ptr<rasterizer::Rasterizer>(
new rasterizer::blitter::HardwareRasterizer(
- graphics_context, options.surface_cache_size_in_bytes));
+ graphics_context, options.scratch_surface_cache_size_in_bytes,
+ options.surface_cache_size_in_bytes));
#endif // COBALT_FORCE_SOFTWARE_RASTERIZER
#else
#error "Either GLES2 or the Starboard Blitter API must be available."
diff --git a/src/cobalt/renderer/sandbox/renderer_sandbox_main.cc b/src/cobalt/renderer/sandbox/renderer_sandbox_main.cc
index dc54939..3fddb14 100644
--- a/src/cobalt/renderer/sandbox/renderer_sandbox_main.cc
+++ b/src/cobalt/renderer/sandbox/renderer_sandbox_main.cc
@@ -30,7 +30,6 @@
using cobalt::render_tree::ResourceProvider;
using cobalt::renderer::test::scenes::AddBlankBackgroundToScene;
using cobalt::renderer::test::scenes::CreateAllScenesCombinedScene;
-using cobalt::renderer::test::scenes::RenderTreeWithAnimations;
using cobalt::system_window::SystemWindow;
namespace {
@@ -67,7 +66,7 @@
// Construct our render tree and associated animations to be passed into
// the renderer pipeline for display.
base::TimeDelta start_time = base::Time::Now() - base::Time::UnixEpoch();
- RenderTreeWithAnimations scene = AddBlankBackgroundToScene(
+ scoped_refptr<cobalt::render_tree::Node> scene = AddBlankBackgroundToScene(
CreateAllScenesCombinedScene(
renderer_module_->pipeline()->GetResourceProvider(),
output_dimensions, start_time),
@@ -75,8 +74,8 @@
// Pass the render tree along with associated animations into the renderer
// module to be displayed.
- renderer_module_->pipeline()->Submit(cobalt::renderer::Submission(
- scene.render_tree, scene.animations, start_time));
+ renderer_module_->pipeline()->Submit(
+ cobalt::renderer::Submission(scene, start_time));
}
RendererSandbox* g_renderer_sandbox = NULL;
diff --git a/src/cobalt/renderer/sandbox/scaling_text_sandbox_main.cc b/src/cobalt/renderer/sandbox/scaling_text_sandbox_main.cc
index 20f2685..71d2f04 100644
--- a/src/cobalt/renderer/sandbox/scaling_text_sandbox_main.cc
+++ b/src/cobalt/renderer/sandbox/scaling_text_sandbox_main.cc
@@ -30,7 +30,6 @@
using cobalt::render_tree::ResourceProvider;
using cobalt::renderer::test::scenes::AddBlankBackgroundToScene;
using cobalt::renderer::test::scenes::CreateScalingTextScene;
-using cobalt::renderer::test::scenes::RenderTreeWithAnimations;
using cobalt::system_window::SystemWindow;
namespace {
@@ -62,15 +61,15 @@
// Construct our render tree and associated animations to be passed into
// the renderer pipeline for display.
base::TimeDelta start_time = base::Time::Now() - base::Time::UnixEpoch();
- RenderTreeWithAnimations scene = AddBlankBackgroundToScene(
+ scoped_refptr<cobalt::render_tree::Node> scene = AddBlankBackgroundToScene(
CreateScalingTextScene(renderer_module.pipeline()->GetResourceProvider(),
output_dimensions, start_time),
output_dimensions);
// Pass the render tree along with associated animations into the renderer
// module to be displayed.
- renderer_module.pipeline()->Submit(cobalt::renderer::Submission(
- scene.render_tree, scene.animations, start_time));
+ renderer_module.pipeline()->Submit(
+ cobalt::renderer::Submission(scene, start_time));
base::PlatformThread::Sleep(base::TimeDelta::FromSeconds(30));
diff --git a/src/cobalt/renderer/submission.h b/src/cobalt/renderer/submission.h
index 7cc86f2..2652e35 100644
--- a/src/cobalt/renderer/submission.h
+++ b/src/cobalt/renderer/submission.h
@@ -21,7 +21,7 @@
#include "base/debug/trace_event.h"
#include "base/memory/ref_counted.h"
#include "base/time.h"
-#include "cobalt/render_tree/animations/node_animations_map.h"
+#include "cobalt/render_tree/animations/animate_node.h"
#include "cobalt/render_tree/node.h"
namespace cobalt {
@@ -32,20 +32,14 @@
// Convenience constructor that assumes there are no animations and sets up
// an empty animation map.
explicit Submission(scoped_refptr<render_tree::Node> render_tree)
- : render_tree(render_tree),
- animations(new render_tree::animations::NodeAnimationsMap(
- render_tree::animations::NodeAnimationsMap::Builder().Pass())) {}
+ : render_tree(render_tree) {}
// Submit a render tree as well as associated animations. The
// time_offset parameter indicates a time that will be used to offset all
// times passed into animation functions.
- Submission(
- scoped_refptr<render_tree::Node> render_tree,
- scoped_refptr<render_tree::animations::NodeAnimationsMap> animations,
- base::TimeDelta time_offset)
- : render_tree(render_tree),
- animations(animations),
- time_offset(time_offset) {}
+ Submission(scoped_refptr<render_tree::Node> render_tree,
+ base::TimeDelta time_offset)
+ : render_tree(render_tree), time_offset(time_offset) {}
~Submission() {
TRACE_EVENT0("cobalt::renderer", "~Submission()");
@@ -53,17 +47,11 @@
// Explicitly dereference the render tree and animation under the scope of
// the above trace event.
render_tree = NULL;
- animations = NULL;
}
// Maintains the current render tree that is to be rendered next frame.
scoped_refptr<render_tree::Node> render_tree;
- // Maintains the current animations that are to be in effect (i.e. applied
- // to current_tree_) for all rasterizations until specifically updated by a
- // call to Submit().
- scoped_refptr<render_tree::animations::NodeAnimationsMap> animations;
-
// The time from some origin that the associated render tree animations were
// created. This permits the render thread to compute times relative
// to the same origin when updating the animations, as well as hinting
diff --git a/src/cobalt/renderer/test/scenes/all_scenes_combined_scene.cc b/src/cobalt/renderer/test/scenes/all_scenes_combined_scene.cc
index ff5045a..133aa88 100644
--- a/src/cobalt/renderer/test/scenes/all_scenes_combined_scene.cc
+++ b/src/cobalt/renderer/test/scenes/all_scenes_combined_scene.cc
@@ -29,48 +29,41 @@
using cobalt::math::SizeF;
using cobalt::render_tree::CompositionNode;
using cobalt::render_tree::ResourceProvider;
-using cobalt::render_tree::animations::NodeAnimationsMap;
+using cobalt::render_tree::animations::AnimateNode;
namespace cobalt {
namespace renderer {
namespace test {
namespace scenes {
-RenderTreeWithAnimations CreateAllScenesCombinedScene(
+scoped_refptr<render_tree::Node> CreateAllScenesCombinedScene(
ResourceProvider* resource_provider, const SizeF& output_dimensions,
base::TimeDelta start_time) {
TRACE_EVENT0("cobalt::renderer_sandbox",
"CreateAllScenesCombinedScene()");
CompositionNode::Builder all_scenes_combined_scene_builder;
- NodeAnimationsMap::Builder animations;
// Compose all the render trees representing the sub-scenes through a
// composition node, and merge the animations into one large set.
- RenderTreeWithAnimations growing_rect_scene =
+ scoped_refptr<render_tree::Node> growing_rect_scene =
CreateGrowingRectScene(output_dimensions, start_time);
- all_scenes_combined_scene_builder.AddChild(growing_rect_scene.render_tree);
- animations.Merge(*growing_rect_scene.animations);
+ all_scenes_combined_scene_builder.AddChild(growing_rect_scene);
- RenderTreeWithAnimations spinning_sprites_scene =
- CreateSpinningSpritesScene(
- resource_provider, output_dimensions, start_time);
- all_scenes_combined_scene_builder.AddChild(
- spinning_sprites_scene.render_tree);
- animations.Merge(*spinning_sprites_scene.animations);
+ scoped_refptr<render_tree::Node> spinning_sprites_scene =
+ CreateSpinningSpritesScene(resource_provider, output_dimensions,
+ start_time);
+ all_scenes_combined_scene_builder.AddChild(spinning_sprites_scene);
- RenderTreeWithAnimations image_wrap_scene =
+ scoped_refptr<render_tree::Node> image_wrap_scene =
CreateImageWrapScene(resource_provider, output_dimensions, start_time);
- all_scenes_combined_scene_builder.AddChild(image_wrap_scene.render_tree);
- animations.Merge(*image_wrap_scene.animations);
+ all_scenes_combined_scene_builder.AddChild(image_wrap_scene);
- RenderTreeWithAnimations marquee_scene =
+ scoped_refptr<render_tree::Node> marquee_scene =
CreateMarqueeScene(resource_provider, output_dimensions, start_time);
- all_scenes_combined_scene_builder.AddChild(marquee_scene.render_tree);
- animations.Merge(*marquee_scene.animations);
+ all_scenes_combined_scene_builder.AddChild(marquee_scene);
- return RenderTreeWithAnimations(
- new CompositionNode(all_scenes_combined_scene_builder.Pass()),
- new NodeAnimationsMap(animations.Pass()));
+ return new AnimateNode(
+ new CompositionNode(all_scenes_combined_scene_builder.Pass()));
}
} // namespace scenes
diff --git a/src/cobalt/renderer/test/scenes/all_scenes_combined_scene.h b/src/cobalt/renderer/test/scenes/all_scenes_combined_scene.h
index 2d098fc..e5c1eec 100644
--- a/src/cobalt/renderer/test/scenes/all_scenes_combined_scene.h
+++ b/src/cobalt/renderer/test/scenes/all_scenes_combined_scene.h
@@ -29,7 +29,7 @@
// This scene will simply composite all other scene types together into one
// mega scene.
-RenderTreeWithAnimations CreateAllScenesCombinedScene(
+scoped_refptr<render_tree::Node> CreateAllScenesCombinedScene(
render_tree::ResourceProvider* resource_provider,
const math::SizeF& output_dimensions, base::TimeDelta start_time);
diff --git a/src/cobalt/renderer/test/scenes/growing_rect_scene.cc b/src/cobalt/renderer/test/scenes/growing_rect_scene.cc
index 54edd16..1f06a4b 100644
--- a/src/cobalt/renderer/test/scenes/growing_rect_scene.cc
+++ b/src/cobalt/renderer/test/scenes/growing_rect_scene.cc
@@ -27,15 +27,15 @@
using cobalt::math::ScaleMatrix;
using cobalt::math::SizeF;
using cobalt::math::TranslateMatrix;
+using cobalt::render_tree::animations::AnimateNode;
+using cobalt::render_tree::animations::Animation;
+using cobalt::render_tree::animations::AnimationList;
using cobalt::render_tree::Brush;
using cobalt::render_tree::ColorRGBA;
using cobalt::render_tree::MatrixTransformNode;
using cobalt::render_tree::Node;
using cobalt::render_tree::RectNode;
using cobalt::render_tree::SolidColorBrush;
-using cobalt::render_tree::animations::Animation;
-using cobalt::render_tree::animations::AnimationList;
-using cobalt::render_tree::animations::NodeAnimationsMap;
namespace cobalt {
namespace renderer {
@@ -62,13 +62,13 @@
} // namespace
-RenderTreeWithAnimations CreateGrowingRectScene(
+scoped_refptr<render_tree::Node> CreateGrowingRectScene(
const math::SizeF& output_dimensions, base::TimeDelta start_time) {
// Create a centered, sawtoothed-growing black rectangle. We need a
// composition node for this so that the rectangle's position can be set
// and animated. We also use the composition node to animate the RectNode's
// size.
- NodeAnimationsMap::Builder animations;
+ AnimateNode::Builder animations;
scoped_refptr<RectNode> growing_rect_node(new RectNode(
math::RectF(output_dimensions),
@@ -81,8 +81,7 @@
base::Bind(&AnimateGrowingRectComposition, start_time,
output_dimensions));
- return RenderTreeWithAnimations(transformed_growing_rect,
- new NodeAnimationsMap(animations.Pass()));
+ return new AnimateNode(animations, transformed_growing_rect);
}
} // namespace scenes
diff --git a/src/cobalt/renderer/test/scenes/growing_rect_scene.h b/src/cobalt/renderer/test/scenes/growing_rect_scene.h
index d57c5b7..9ffabbc 100644
--- a/src/cobalt/renderer/test/scenes/growing_rect_scene.h
+++ b/src/cobalt/renderer/test/scenes/growing_rect_scene.h
@@ -28,7 +28,7 @@
// This scene gives a gray rectangle centered in the screen that slowly grows
// to fill the screen.
-RenderTreeWithAnimations CreateGrowingRectScene(
+scoped_refptr<render_tree::Node> CreateGrowingRectScene(
const math::SizeF& output_dimensions, base::TimeDelta start_time);
} // namespace scenes
diff --git a/src/cobalt/renderer/test/scenes/image_wrap_scene.cc b/src/cobalt/renderer/test/scenes/image_wrap_scene.cc
index ee70281..1add5b4 100644
--- a/src/cobalt/renderer/test/scenes/image_wrap_scene.cc
+++ b/src/cobalt/renderer/test/scenes/image_wrap_scene.cc
@@ -34,15 +34,15 @@
using cobalt::math::Matrix3F;
using cobalt::math::SizeF;
+using cobalt::render_tree::animations::AnimateNode;
+using cobalt::render_tree::animations::Animation;
+using cobalt::render_tree::animations::AnimationList;
using cobalt::render_tree::CompositionNode;
using cobalt::render_tree::Image;
using cobalt::render_tree::ImageNode;
using cobalt::render_tree::MatrixTransformNode;
using cobalt::render_tree::Node;
using cobalt::render_tree::ResourceProvider;
-using cobalt::render_tree::animations::Animation;
-using cobalt::render_tree::animations::AnimationList;
-using cobalt::render_tree::animations::NodeAnimationsMap;
using cobalt::renderer::test::png_utils::DecodePNGToRenderTreeImage;
namespace cobalt {
@@ -89,10 +89,10 @@
} // namespace
-RenderTreeWithAnimations CreateImageWrapScene(
+scoped_refptr<render_tree::Node> CreateImageWrapScene(
ResourceProvider* resource_provider, const math::SizeF& output_dimensions,
base::TimeDelta start_time) {
- NodeAnimationsMap::Builder animations;
+ AnimateNode::Builder animations;
// Create an image node that will have its local_transform animated to
// demonstrate what local_transform allows one to do.
@@ -107,8 +107,7 @@
animations.Add(image_node, base::Bind(&AnimateImage, start_time));
- return RenderTreeWithAnimations(
- image_wrap_scene, new NodeAnimationsMap(animations.Pass()));
+ return new AnimateNode(animations, image_wrap_scene);
}
} // namespace scenes
diff --git a/src/cobalt/renderer/test/scenes/image_wrap_scene.h b/src/cobalt/renderer/test/scenes/image_wrap_scene.h
index 4c2d631..27726ff 100644
--- a/src/cobalt/renderer/test/scenes/image_wrap_scene.h
+++ b/src/cobalt/renderer/test/scenes/image_wrap_scene.h
@@ -31,7 +31,7 @@
// shrunk, and so the texture repeats to fill the size of the image node.
// The texture is also spinning. This scene effectively shows off
// ImageNode's local_matrix parameter.
-RenderTreeWithAnimations CreateImageWrapScene(
+scoped_refptr<render_tree::Node> CreateImageWrapScene(
render_tree::ResourceProvider* resource_provider,
const math::SizeF& output_dimensions, base::TimeDelta start_time);
diff --git a/src/cobalt/renderer/test/scenes/marquee_scene.cc b/src/cobalt/renderer/test/scenes/marquee_scene.cc
index f2630ce..3d44382 100644
--- a/src/cobalt/renderer/test/scenes/marquee_scene.cc
+++ b/src/cobalt/renderer/test/scenes/marquee_scene.cc
@@ -33,6 +33,9 @@
using cobalt::math::RectF;
using cobalt::math::SizeF;
using cobalt::math::TranslateMatrix;
+using cobalt::render_tree::animations::AnimateNode;
+using cobalt::render_tree::animations::Animation;
+using cobalt::render_tree::animations::AnimationList;
using cobalt::render_tree::Brush;
using cobalt::render_tree::ColorRGBA;
using cobalt::render_tree::CompositionNode;
@@ -45,9 +48,6 @@
using cobalt::render_tree::ResourceProvider;
using cobalt::render_tree::SolidColorBrush;
using cobalt::render_tree::TextNode;
-using cobalt::render_tree::animations::Animation;
-using cobalt::render_tree::animations::AnimationList;
-using cobalt::render_tree::animations::NodeAnimationsMap;
namespace cobalt {
namespace renderer {
@@ -85,11 +85,11 @@
} // namespace
-RenderTreeWithAnimations CreateMarqueeScene(
+scoped_refptr<render_tree::Node> CreateMarqueeScene(
ResourceProvider* resource_provider, const math::SizeF& output_dimensions,
base::TimeDelta start_time) {
CompositionNode::Builder marquee_scene_builder;
- NodeAnimationsMap::Builder animations;
+ AnimateNode::Builder animations;
const std::string kMarqueeText("YouTube");
@@ -130,8 +130,7 @@
animations.Add(marquee_node, base::Bind(&AnimateMarqueeElement, start_time,
text_bounds, output_dimensions));
- return RenderTreeWithAnimations(marquee_node,
- new NodeAnimationsMap(animations.Pass()));
+ return new AnimateNode(animations, marquee_node);
}
} // namespace scenes
diff --git a/src/cobalt/renderer/test/scenes/marquee_scene.h b/src/cobalt/renderer/test/scenes/marquee_scene.h
index 0d15965..5b2055a 100644
--- a/src/cobalt/renderer/test/scenes/marquee_scene.h
+++ b/src/cobalt/renderer/test/scenes/marquee_scene.h
@@ -29,7 +29,7 @@
// This render tree builder will create a scene containing highlighted
// text scrolling smoothly from left to right.
-RenderTreeWithAnimations CreateMarqueeScene(
+scoped_refptr<render_tree::Node> CreateMarqueeScene(
render_tree::ResourceProvider* resource_provider,
const math::SizeF& output_dimensions, base::TimeDelta start_time);
diff --git a/src/cobalt/renderer/test/scenes/scaling_text_scene.cc b/src/cobalt/renderer/test/scenes/scaling_text_scene.cc
index 4ac33b5..952b03b 100644
--- a/src/cobalt/renderer/test/scenes/scaling_text_scene.cc
+++ b/src/cobalt/renderer/test/scenes/scaling_text_scene.cc
@@ -45,7 +45,7 @@
using cobalt::render_tree::TextNode;
using cobalt::render_tree::animations::Animation;
using cobalt::render_tree::animations::AnimationList;
-using cobalt::render_tree::animations::NodeAnimationsMap;
+using cobalt::render_tree::animations::AnimateNode;
namespace cobalt {
namespace renderer {
@@ -62,7 +62,7 @@
} // namespace
-RenderTreeWithAnimations CreateScalingTextScene(
+scoped_refptr<render_tree::Node> CreateScalingTextScene(
ResourceProvider* resource_provider, const math::SizeF& output_dimensions,
base::TimeDelta start_time) {
const std::string kText(
@@ -91,11 +91,10 @@
Matrix3F::Identity()));
// Setup the scaling animation on the text
- NodeAnimationsMap::Builder animations;
+ AnimateNode::Builder animations;
animations.Add(scaling_text_node, base::Bind(&ScaleText));
- return RenderTreeWithAnimations(scaling_text_node,
- new NodeAnimationsMap(animations.Pass()));
+ return new AnimateNode(animations, scaling_text_node);
}
} // namespace scenes
diff --git a/src/cobalt/renderer/test/scenes/scaling_text_scene.h b/src/cobalt/renderer/test/scenes/scaling_text_scene.h
index c6d8771..4b3226d 100644
--- a/src/cobalt/renderer/test/scenes/scaling_text_scene.h
+++ b/src/cobalt/renderer/test/scenes/scaling_text_scene.h
@@ -31,7 +31,7 @@
// scale being applied to it, and the scale of all text is animated.
// This is very useful for investigating issues with text scaling, which
// internally can be quite non-trivial.
-RenderTreeWithAnimations CreateScalingTextScene(
+scoped_refptr<render_tree::Node> CreateScalingTextScene(
render_tree::ResourceProvider* resource_provider,
const math::SizeF& output_dimensions, base::TimeDelta start_time);
diff --git a/src/cobalt/renderer/test/scenes/scene_helpers.cc b/src/cobalt/renderer/test/scenes/scene_helpers.cc
index 724142c..39aa8d5 100644
--- a/src/cobalt/renderer/test/scenes/scene_helpers.cc
+++ b/src/cobalt/renderer/test/scenes/scene_helpers.cc
@@ -36,8 +36,8 @@
namespace test {
namespace scenes {
-RenderTreeWithAnimations AddBlankBackgroundToScene(
- const RenderTreeWithAnimations& scene,
+scoped_refptr<render_tree::Node> AddBlankBackgroundToScene(
+ const scoped_refptr<render_tree::Node>& scene,
const SizeF& output_dimensions) {
// Declare a rectangle that fills the background to effectively clear the
// screen.
@@ -45,10 +45,10 @@
with_background_scene_builder.AddChild(make_scoped_refptr(new RectNode(
RectF(output_dimensions),
scoped_ptr<Brush>(new SolidColorBrush(ColorRGBA(1.0f, 1.0f, 1.0f))))));
- with_background_scene_builder.AddChild(scene.render_tree);
+ with_background_scene_builder.AddChild(scene);
- return RenderTreeWithAnimations(new CompositionNode(
- with_background_scene_builder.Pass()), scene.animations);
+ return new render_tree::animations::AnimateNode(
+ new CompositionNode(with_background_scene_builder.Pass()));
}
} // namespace scenes
diff --git a/src/cobalt/renderer/test/scenes/scene_helpers.h b/src/cobalt/renderer/test/scenes/scene_helpers.h
index 67b6ab1..7c84d41 100644
--- a/src/cobalt/renderer/test/scenes/scene_helpers.h
+++ b/src/cobalt/renderer/test/scenes/scene_helpers.h
@@ -18,7 +18,7 @@
#define COBALT_RENDERER_TEST_SCENES_SCENE_HELPERS_H_
#include "cobalt/math/size_f.h"
-#include "cobalt/render_tree/animations/node_animations_map.h"
+#include "cobalt/render_tree/animations/animate_node.h"
#include "cobalt/render_tree/node.h"
namespace cobalt {
@@ -30,18 +30,8 @@
// animations.
inline float Sawtooth(float x) { return x - static_cast<int>(x); }
-struct RenderTreeWithAnimations {
- RenderTreeWithAnimations(
- scoped_refptr<render_tree::Node> render_tree,
- scoped_refptr<render_tree::animations::NodeAnimationsMap> animations)
- : render_tree(render_tree), animations(animations) {}
-
- scoped_refptr<render_tree::Node> render_tree;
- scoped_refptr<render_tree::animations::NodeAnimationsMap> animations;
-};
-
-RenderTreeWithAnimations AddBlankBackgroundToScene(
- const RenderTreeWithAnimations& scene,
+scoped_refptr<render_tree::Node> AddBlankBackgroundToScene(
+ const scoped_refptr<render_tree::Node>& scene,
const math::SizeF& output_dimensions);
} // namespace scenes
diff --git a/src/cobalt/renderer/test/scenes/spinning_sprites_scene.cc b/src/cobalt/renderer/test/scenes/spinning_sprites_scene.cc
index c338454..e54d4b0 100644
--- a/src/cobalt/renderer/test/scenes/spinning_sprites_scene.cc
+++ b/src/cobalt/renderer/test/scenes/spinning_sprites_scene.cc
@@ -35,20 +35,20 @@
using cobalt::math::Matrix3F;
using cobalt::math::PointF;
-using cobalt::math::RotateMatrix;
using cobalt::math::RectF;
+using cobalt::math::RotateMatrix;
using cobalt::math::ScaleMatrix;
using cobalt::math::SizeF;
using cobalt::math::TranslateMatrix;
+using cobalt::render_tree::animations::AnimateNode;
+using cobalt::render_tree::animations::Animation;
+using cobalt::render_tree::animations::AnimationList;
using cobalt::render_tree::CompositionNode;
using cobalt::render_tree::Image;
using cobalt::render_tree::ImageNode;
using cobalt::render_tree::MatrixTransformNode;
using cobalt::render_tree::Node;
using cobalt::render_tree::ResourceProvider;
-using cobalt::render_tree::animations::Animation;
-using cobalt::render_tree::animations::AnimationList;
-using cobalt::render_tree::animations::NodeAnimationsMap;
using cobalt::renderer::test::png_utils::DecodePNGToRenderTreeImage;
namespace cobalt {
@@ -118,14 +118,14 @@
} // namespace
-RenderTreeWithAnimations CreateSpinningSpritesScene(
+scoped_refptr<render_tree::Node> CreateSpinningSpritesScene(
ResourceProvider* resource_provider, const math::SizeF& output_dimensions,
base::TimeDelta start_time) {
// Create an image for each SpriteInfo we have in our sprite_infos vector.
// They will be positioned and scaled according to their SpriteInfo settings,
// and rotated according to time.
CompositionNode::Builder spinning_sprites_scene_builder;
- NodeAnimationsMap::Builder animations;
+ AnimateNode::Builder animations;
// Now, setup a plurality of spinning images that contain the test image.
std::vector<SpriteInfo> sprite_infos = CreateSpriteInfos();
@@ -154,8 +154,7 @@
scoped_refptr<CompositionNode> spinning_sprites_composition(
new CompositionNode(spinning_sprites_scene_builder.Pass()));
- return RenderTreeWithAnimations(spinning_sprites_composition,
- new NodeAnimationsMap(animations.Pass()));
+ return new AnimateNode(animations, spinning_sprites_composition);
}
} // namespace scenes
diff --git a/src/cobalt/renderer/test/scenes/spinning_sprites_scene.h b/src/cobalt/renderer/test/scenes/spinning_sprites_scene.h
index 9e56e63..56595ab 100644
--- a/src/cobalt/renderer/test/scenes/spinning_sprites_scene.h
+++ b/src/cobalt/renderer/test/scenes/spinning_sprites_scene.h
@@ -29,7 +29,7 @@
// This scene will create a plurality of randomly positioned and sized sprites
// that are all spinning at different rates.
-RenderTreeWithAnimations CreateSpinningSpritesScene(
+scoped_refptr<render_tree::Node> CreateSpinningSpritesScene(
render_tree::ResourceProvider* resource_provider,
const math::SizeF& output_dimensions, base::TimeDelta start_time);
diff --git a/src/cobalt/script/javascriptcore/jsc_global_object.cc b/src/cobalt/script/javascriptcore/jsc_global_object.cc
index 6596d1b..9122348 100644
--- a/src/cobalt/script/javascriptcore/jsc_global_object.cc
+++ b/src/cobalt/script/javascriptcore/jsc_global_object.cc
@@ -17,6 +17,7 @@
#include "cobalt/script/javascriptcore/jsc_global_object.h"
#include "base/logging.h"
+#include "cobalt/script/javascriptcore/util/exception_helpers.h"
namespace cobalt {
namespace script {
@@ -57,6 +58,10 @@
script_object_registry_(script_object_registry),
environment_settings_(environment_settings) {}
+std::vector<script::StackFrame> JSCGlobalObject::GetStackTrace(int max_frames) {
+ return util::GetStackTrace(globalExec(), max_frames);
+}
+
} // namespace javascriptcore
} // namespace script
} // namespace cobalt
diff --git a/src/cobalt/script/javascriptcore/jsc_global_object.h b/src/cobalt/script/javascriptcore/jsc_global_object.h
index 9671b44..89f0dc6 100644
--- a/src/cobalt/script/javascriptcore/jsc_global_object.h
+++ b/src/cobalt/script/javascriptcore/jsc_global_object.h
@@ -26,6 +26,7 @@
#include "cobalt/script/javascriptcore/js_object_cache.h"
#include "cobalt/script/javascriptcore/script_object_registry.h"
#include "cobalt/script/javascriptcore/wrapper_factory.h"
+#include "cobalt/script/stack_frame.h"
#include "cobalt/script/wrappable.h"
#include "third_party/WebKit/Source/JavaScriptCore/config.h"
#include "third_party/WebKit/Source/JavaScriptCore/runtime/JSGlobalData.h"
@@ -59,6 +60,7 @@
EnvironmentSettings* GetEnvironmentSettings() {
return environment_settings_;
}
+ std::vector<StackFrame> GetStackTrace(int max_frames = 0);
// JavaScriptCore stuff
DECLARE_CLASSINFO();
diff --git a/src/cobalt/script/mozjs/mozjs.cc b/src/cobalt/script/mozjs/mozjs.cc
index 0de17d2..6625ed2 100644
--- a/src/cobalt/script/mozjs/mozjs.cc
+++ b/src/cobalt/script/mozjs/mozjs.cc
@@ -21,8 +21,10 @@
#include "base/string_util.h"
#include "cobalt/base/wrap_main.h"
#include "cobalt/script/mozjs/mozjs_global_object_proxy.h"
+#include "cobalt/script/source_code.h"
#include "cobalt/script/standalone_javascript_runner.h"
#include "third_party/mozjs/js/src/jsapi.h"
+#include "third_party/mozjs/js/src/jsproxy.h"
namespace cobalt {
namespace script {
@@ -50,6 +52,8 @@
}
void SetupBindings(JSContext* context, JSObject* global_object) {
+ DCHECK(JS_IsGlobalObject(global_object));
+
JSAutoRequest auto_request(context);
JSAutoCompartment auto_comparment(context, global_object);
JS_DefineFunction(context, global_object, "print", &Print, 0,
@@ -58,18 +62,43 @@
int MozjsMain(int argc, char** argv) {
cobalt::script::StandaloneJavascriptRunner standalone_runner;
- MozjsGlobalObjectProxy* global_object_proxy =
+ MozjsGlobalObjectProxy* global_object_environment =
static_cast<MozjsGlobalObjectProxy*>(
standalone_runner.global_object_proxy().get());
- SetupBindings(global_object_proxy->context(),
- global_object_proxy->global_object());
+ SetupBindings(global_object_environment->context(),
+ global_object_environment->global_object());
- CommandLine command_line(argc, argv);
- CommandLine::StringVector args = command_line.GetArgs();
- if (!args.empty()) {
- FilePath source_file(args[0]);
- standalone_runner.ExecuteFile(source_file);
+ if (argc > 1) {
+ // Command line arguments will be flag-value pairs of the form
+ // -f filename
+ // and
+ // -e "inline script"
+ // and will be evaluated in order.
+ for (int i = 1; (i + 1) < argc; ++i) {
+ if (std::string(argv[i]) == "-f") {
+ std::string filename = std::string(argv[i + 1]);
+ // Execute source file.
+ FilePath source_file(filename);
+ standalone_runner.ExecuteFile(source_file);
+ ++i;
+ } else if (std::string(argv[i]) == "-e") {
+ // Execute inline script.
+ scoped_refptr<SourceCode> source = SourceCode::CreateSourceCode(
+ argv[i + 1], base::SourceLocation("[stdin]", 1, 1));
+
+ // Execute the script and get the results of execution.
+ std::string result;
+ bool success =
+ global_object_environment->EvaluateScript(source, &result);
+ // Echo the results to stdout.
+ if (!success) {
+ std::cout << "Exception: ";
+ }
+ std::cout << result << std::endl;
+ ++i;
+ }
+ }
} else {
standalone_runner.RunInteractive();
}
diff --git a/src/cobalt/script/mozjs/mozjs.gyp b/src/cobalt/script/mozjs/mozjs.gyp
index 58728de..49f8313 100644
--- a/src/cobalt/script/mozjs/mozjs.gyp
+++ b/src/cobalt/script/mozjs/mozjs.gyp
@@ -27,6 +27,7 @@
'mozjs_property_enumerator.cc',
'mozjs_source_code.cc',
'proxy_handler.cc',
+ 'util/exception_helpers.cc',
'wrapper_factory.cc',
'wrapper_private.cc',
],
@@ -41,6 +42,11 @@
'ENGINE_SUPPORTS_INDEXED_DELETERS',
'ENGINE_SUPPORTS_INT64', ],
},
+ 'conditions' :[
+ ['cobalt_enable_jit == 1', {
+ 'defines': [ 'ENGINE_SUPPORTS_JIT', ],
+ }],
+ ],
},
{
diff --git a/src/cobalt/script/mozjs/mozjs_exception_state.cc b/src/cobalt/script/mozjs/mozjs_exception_state.cc
index a4c575b..e7839c4 100644
--- a/src/cobalt/script/mozjs/mozjs_exception_state.cc
+++ b/src/cobalt/script/mozjs/mozjs_exception_state.cc
@@ -49,7 +49,18 @@
void MozjsExceptionState::SetException(
const scoped_refptr<ScriptException>& exception) {
DCHECK(thread_checker_.CalledOnValidThread());
- NOTIMPLEMENTED();
+ DCHECK(!is_exception_set_);
+
+ MozjsGlobalObjectProxy* global_object_proxy =
+ static_cast<MozjsGlobalObjectProxy*>(JS_GetContextPrivate(context_));
+
+ JS::RootedObject exception_object(
+ context_,
+ global_object_proxy->wrapper_factory()->GetWrapperProxy(exception));
+ JS::RootedValue exception_value(context_, OBJECT_TO_JSVAL(exception_object));
+ JS_SetPendingException(context_, exception_value);
+
+ is_exception_set_ = true;
}
void MozjsExceptionState::SetSimpleException(
diff --git a/src/cobalt/script/mozjs/mozjs_global_object_proxy.cc b/src/cobalt/script/mozjs/mozjs_global_object_proxy.cc
index 43c45bc..8622146 100644
--- a/src/cobalt/script/mozjs/mozjs_global_object_proxy.cc
+++ b/src/cobalt/script/mozjs/mozjs_global_object_proxy.cc
@@ -15,13 +15,18 @@
*/
#include "cobalt/script/mozjs/mozjs_global_object_proxy.h"
+#include <algorithm>
#include <utility>
+#include "base/lazy_instance.h"
#include "base/stringprintf.h"
#include "cobalt/base/polymorphic_downcast.h"
#include "cobalt/script/mozjs/conversion_helpers.h"
#include "cobalt/script/mozjs/mozjs_exception_state.h"
#include "cobalt/script/mozjs/mozjs_source_code.h"
+#include "cobalt/script/mozjs/mozjs_wrapper_handle.h"
+#include "cobalt/script/mozjs/proxy_handler.h"
+#include "cobalt/script/mozjs/util/exception_helpers.h"
#include "third_party/mozjs/js/src/jsfriendapi.h"
#include "third_party/mozjs/js/src/jsfun.h"
#include "third_party/mozjs/js/src/jsobj.h"
@@ -66,6 +71,52 @@
// This is the default in the spidermonkey shell.
const uint32_t kMaxCodeCacheBytes = 16 * 1024 * 1024;
+
+// DOM proxies have an extra slot for the expando object at index
+// kJSProxySlotExpando.
+// The expando object is a plain JSObject whose properties correspond to
+// "expandos" (custom properties set by the script author).
+// The exact value stored in the kJSProxySlotExpando slot depends on whether
+// the interface is annotated with the [OverrideBuiltins] extended attribute.
+const uint32_t kJSProxySlotExpando = 0;
+
+// The DOMProxyShadowsCheck function will be called to check if the property for
+// id should be gotten from the prototype, or if there is an own property that
+// shadows it.
+js::DOMProxyShadowsResult DOMProxyShadowsCheck(JSContext* context,
+ JS::HandleObject proxy,
+ JS::HandleId id) {
+ DCHECK(IsProxy(proxy));
+ JS::Value value = js::GetProxyExtra(proxy, kJSProxySlotExpando);
+ DCHECK(value.isUndefined() || value.isObject());
+
+ // [OverrideBuiltins] extended attribute is not supported.
+ NOTIMPLEMENTED();
+
+ // If DoesntShadow is returned then the slot at listBaseExpandoSlot should
+ // either be undefined or point to an expando object that would contain the
+ // own property.
+ return js::DoesntShadow;
+}
+
+class MozjsStubHandler : public ProxyHandler {
+ public:
+ MozjsStubHandler()
+ : ProxyHandler(indexed_property_hooks, named_property_hooks) {}
+
+ private:
+ static NamedPropertyHooks named_property_hooks;
+ static IndexedPropertyHooks indexed_property_hooks;
+};
+
+ProxyHandler::NamedPropertyHooks MozjsStubHandler::named_property_hooks = {
+ NULL, NULL, NULL, NULL, NULL,
+};
+ProxyHandler::IndexedPropertyHooks MozjsStubHandler::indexed_property_hooks = {
+ NULL, NULL, NULL, NULL, NULL,
+};
+
+static base::LazyInstance<MozjsStubHandler> proxy_handler;
} // namespace
MozjsGlobalObjectProxy::MozjsGlobalObjectProxy(JSRuntime* runtime)
@@ -82,16 +133,18 @@
JS_SetGCParameterForThread(context_, JSGC_MAX_CODE_CACHE_BYTES,
kMaxCodeCacheBytes);
-
uint32_t options =
JSOPTION_TYPE_INFERENCE |
JSOPTION_VAROBJFIX | // Recommended to enable this in the API docs.
JSOPTION_COMPILE_N_GO | // Compiled scripts will be run only once.
JSOPTION_UNROOTED_GLOBAL; // Global handle must be visited to ensure it
// is not GC'd.
-#if SB_CAN(MAP_EXECUTABLE_MEMORY)
+#if ENGINE_SUPPORTS_JIT
options |= JSOPTION_BASELINE | // Enable baseline compiler.
JSOPTION_ION; // Enable IonMonkey
+ // This is required by baseline and IonMonkey.
+ js::SetDOMProxyInformation(0 /*domProxyHandlerFamily*/, kJSProxySlotExpando,
+ DOMProxyShadowsCheck);
#endif
#if !defined(COBALT_BUILD_TYPE_GOLD) && !defined(COBALT_BUILD_TYPE_QA)
options |= JSOPTION_EXTRA_WARNINGS;
@@ -101,6 +154,7 @@
JS_SetErrorReporter(context_, &MozjsGlobalObjectProxy::ReportErrorHandler);
wrapper_factory_.reset(new WrapperFactory(context_));
+
JS_AddExtraGCRootsTracer(runtime, TraceFunction, this);
}
@@ -111,7 +165,7 @@
void MozjsGlobalObjectProxy::CreateGlobalObject() {
DCHECK(thread_checker_.CalledOnValidThread());
- DCHECK(!global_object_);
+ DCHECK(!global_object_proxy_);
// The global object is automatically rooted unless the
// JSOPTION_UNROOTED_GLOBAL option is set.
@@ -128,7 +182,11 @@
JSAutoCompartment auto_compartment(context_, global_object);
bool success = JS_InitStandardClasses(context_, global_object);
DCHECK(success);
- SetGlobalObject(global_object);
+
+ JS::RootedObject proxy(
+ context_, ProxyHandler::NewProxy(context_, global_object, NULL, NULL,
+ proxy_handler.Pointer()));
+ global_object_proxy_ = proxy;
}
bool MozjsGlobalObjectProxy::EvaluateScript(
@@ -142,12 +200,14 @@
const base::SourceLocation location = mozjs_source_code->location();
JSAutoRequest auto_request(context_);
- JSAutoCompartment auto_comparment(context_, global_object_);
+ JSAutoCompartment auto_comparment(context_, global_object_proxy_);
JS::RootedValue result_value(context_);
std::string error_message;
last_error_message_ = &error_message;
+ JS::RootedObject global_object(
+ context_, js::GetProxyTargetObject(global_object_proxy_));
bool success = JS_EvaluateScript(
- context_, global_object_, script.c_str(), script.size(),
+ context_, global_object, script.c_str(), script.size(),
location.file_path.c_str(), location.line_number, result_value.address());
if (out_result_utf8) {
if (success) {
@@ -162,6 +222,11 @@
return success;
}
+std::vector<StackFrame> MozjsGlobalObjectProxy::GetStackTrace(int max_frames) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ return util::GetStackTrace(context_, max_frames);
+}
+
void MozjsGlobalObjectProxy::DisableEval(const std::string& message) {
DCHECK(thread_checker_.CalledOnValidThread());
eval_disabled_message_.emplace(message);
@@ -183,11 +248,14 @@
void MozjsGlobalObjectProxy::Bind(const std::string& identifier,
const scoped_refptr<Wrappable>& impl) {
JSAutoRequest auto_request(context_);
- JSAutoCompartment auto_comparment(context_, global_object_);
+ JSAutoCompartment auto_comparment(context_, global_object_proxy_);
+
JS::RootedObject wrapper_proxy(context_,
wrapper_factory_->GetWrapperProxy(impl));
+ JS::RootedObject global_object(
+ context_, js::GetProxyTargetObject(global_object_proxy_));
JS::Value wrapper_value = OBJECT_TO_JSVAL(wrapper_proxy);
- bool success = JS_SetProperty(context_, global_object_, identifier.c_str(),
+ bool success = JS_SetProperty(context_, global_object, identifier.c_str(),
&wrapper_value);
DCHECK(success);
}
@@ -208,6 +276,28 @@
return global_proxy;
}
+void MozjsGlobalObjectProxy::SetGlobalObjectProxyAndWrapper(
+ JS::HandleObject global_object_proxy,
+ const scoped_refptr<Wrappable>& wrappable) {
+ DCHECK(!global_object_proxy_);
+ DCHECK(global_object_proxy);
+ DCHECK(JS_IsGlobalObject(js::GetProxyTargetObject(global_object_proxy)));
+ DCHECK(IsObjectProxy(global_object_proxy));
+
+ global_object_proxy_ = global_object_proxy;
+
+ // Global object cached wrapper is not set as usual object.
+ // Set the global object cached wrapper, so we can get the object proxy
+ // through wrapper handle.
+ WrapperPrivate* wrapper_private =
+ WrapperPrivate::GetFromProxyObject(context_, global_object_proxy_);
+ DCHECK(wrapper_private);
+
+ scoped_ptr<Wrappable::WeakWrapperHandle> object_handle(
+ new MozjsWrapperHandle(wrapper_private));
+ SetCachedWrapper(wrappable.get(), object_handle.Pass());
+}
+
void MozjsGlobalObjectProxy::CacheInterfaceData(intptr_t key,
InterfaceData* interface_data) {
std::pair<CachedInterfaceData::iterator, bool> pib =
@@ -235,15 +325,16 @@
}
void MozjsGlobalObjectProxy::TraceFunction(JSTracer* trace, void* data) {
- MozjsGlobalObjectProxy* global_object_proxy =
+ MozjsGlobalObjectProxy* global_object_environment =
reinterpret_cast<MozjsGlobalObjectProxy*>(data);
- if (global_object_proxy->global_object_) {
- JS_CallHeapObjectTracer(trace, &global_object_proxy->global_object_,
+ if (global_object_environment->global_object_proxy_) {
+ JS_CallHeapObjectTracer(trace,
+ &global_object_environment->global_object_proxy_,
"MozjsGlobalObjectProxy");
}
for (CachedInterfaceData::iterator it =
- global_object_proxy->cached_interface_data_.begin();
- it != global_object_proxy->cached_interface_data_.end(); ++it) {
+ global_object_environment->cached_interface_data_.begin();
+ it != global_object_environment->cached_interface_data_.end(); ++it) {
InterfaceData* data = it->second;
JS_CallHeapObjectTracer(trace, &data->prototype, "MozjsGlobalObjectProxy");
JS_CallHeapObjectTracer(trace, &data->interface_object,
diff --git a/src/cobalt/script/mozjs/mozjs_global_object_proxy.h b/src/cobalt/script/mozjs/mozjs_global_object_proxy.h
index decac4e..0355d37 100644
--- a/src/cobalt/script/mozjs/mozjs_global_object_proxy.h
+++ b/src/cobalt/script/mozjs/mozjs_global_object_proxy.h
@@ -26,8 +26,10 @@
#include "base/threading/thread_checker.h"
#include "cobalt/script/global_object_proxy.h"
#include "cobalt/script/mozjs/interface_data.h"
+#include "cobalt/script/mozjs/util/exception_helpers.h"
#include "cobalt/script/mozjs/wrapper_factory.h"
#include "third_party/mozjs/js/src/jsapi.h"
+#include "third_party/mozjs/js/src/jsproxy.h"
namespace cobalt {
namespace script {
@@ -35,7 +37,8 @@
// Manages a handle to a JavaScript engine's global object. The lifetime of
// the global object is not necessarily tied to the lifetime of the proxy.
-class MozjsGlobalObjectProxy : public GlobalObjectProxy {
+class MozjsGlobalObjectProxy : public GlobalObjectProxy,
+ public Wrappable::CachedWrapperAccessor {
public:
explicit MozjsGlobalObjectProxy(JSRuntime* runtime);
~MozjsGlobalObjectProxy() OVERRIDE;
@@ -53,10 +56,7 @@
return false;
}
- std::vector<StackFrame> GetStackTrace(int max_frames) OVERRIDE {
- NOTIMPLEMENTED();
- return std::vector<StackFrame>();
- }
+ std::vector<StackFrame> GetStackTrace(int max_frames = 0) OVERRIDE;
void PreventGarbageCollection(
const scoped_refptr<Wrappable>& wrappable) OVERRIDE {
@@ -79,7 +79,10 @@
JSContext* context() const { return context_; }
- JSObject* global_object() const { return global_object_; }
+ JSObject* global_object_proxy() const { return global_object_proxy_; }
+ JSObject* global_object() const {
+ return js::GetProxyTargetObject(global_object_proxy_);
+ }
WrapperFactory* wrapper_factory() { return wrapper_factory_.get(); }
@@ -94,11 +97,9 @@
return environment_settings_;
}
- void SetGlobalObject(JS::HandleObject global_object) {
- DCHECK(!global_object_);
- DCHECK(global_object);
- global_object_ = global_object;
- }
+ void SetGlobalObjectProxyAndWrapper(
+ JS::HandleObject global_object_proxy,
+ const scoped_refptr<Wrappable>& wrappable);
// Any tracked InterfaceData will have it's GC handles visited and marked as
// roots. The MozjsGlobalObjectProxy takes ownership of the InterfaceData
@@ -135,7 +136,7 @@
STLValueDeleter<CachedInterfaceData> cached_interface_data_deleter_;
ContextDestructor context_destructor_;
scoped_ptr<WrapperFactory> wrapper_factory_;
- JS::Heap<JSObject*> global_object_;
+ JS::Heap<JSObject*> global_object_proxy_;
EnvironmentSettings* environment_settings_;
// If non-NULL, the error message from the ReportErrorHandler will get
diff --git a/src/cobalt/script/mozjs/mozjs_user_object_holder.h b/src/cobalt/script/mozjs/mozjs_user_object_holder.h
index 0551bff..de47435 100644
--- a/src/cobalt/script/mozjs/mozjs_user_object_holder.h
+++ b/src/cobalt/script/mozjs/mozjs_user_object_holder.h
@@ -16,6 +16,8 @@
#ifndef COBALT_SCRIPT_MOZJS_MOZJS_USER_OBJECT_HOLDER_H_
#define COBALT_SCRIPT_MOZJS_MOZJS_USER_OBJECT_HOLDER_H_
+#include "base/hash_tables.h"
+#include "base/memory/weak_ptr.h"
#include "cobalt/base/polymorphic_downcast.h"
#include "cobalt/script/mozjs/wrapper_factory.h"
#include "cobalt/script/mozjs/wrapper_private.h"
@@ -50,14 +52,21 @@
JS::RootedObject owned_object(context_, js_object());
WrapperPrivate* wrapper_private =
WrapperPrivate::GetFromWrappable(owner, context_, wrapper_factory_);
+ wrappable_and_private_hash_map_.insert(
+ std::make_pair(owner, wrapper_private->AsWeakPtr()));
wrapper_private->AddReferencedObject(owned_object);
}
void DeregisterOwner(Wrappable* owner) OVERRIDE {
JS::RootedObject owned_object(context_, js_object());
- WrapperPrivate* wrapper_private =
- WrapperPrivate::GetFromWrappable(owner, context_, wrapper_factory_);
- wrapper_private->RemoveReferencedObject(owned_object);
+ WrappableAndPrivateHashMap::iterator it =
+ wrappable_and_private_hash_map_.find(owner);
+ if (it != wrappable_and_private_hash_map_.end() && it->second) {
+ JS::RootedObject object_proxy(context_, it->second->js_object_proxy());
+ if (object_proxy) {
+ it->second->RemoveReferencedObject(owned_object);
+ }
+ }
}
const typename MozjsUserObjectType::BaseType* GetScriptObject()
@@ -89,9 +98,13 @@
}
private:
+ typedef base::hash_map<const Wrappable*, base::WeakPtr<WrapperPrivate> >
+ WrappableAndPrivateHashMap;
+
JSContext* context_;
base::optional<MozjsUserObjectType> object_handle_;
WrapperFactory* wrapper_factory_;
+ WrappableAndPrivateHashMap wrappable_and_private_hash_map_;
};
} // namespace mozjs
diff --git a/src/cobalt/script/mozjs/util/exception_helpers.cc b/src/cobalt/script/mozjs/util/exception_helpers.cc
new file mode 100644
index 0000000..9ef7f2c
--- /dev/null
+++ b/src/cobalt/script/mozjs/util/exception_helpers.cc
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2016 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 "cobalt/script/mozjs/util/exception_helpers.h"
+
+#include <algorithm>
+
+#include "cobalt/script/mozjs/conversion_helpers.h"
+#include "cobalt/script/mozjs/mozjs_exception_state.h"
+#include "third_party/mozjs/js/src/jsdbgapi.h"
+#include "third_party/mozjs/js/src/jsscript.h"
+
+namespace cobalt {
+namespace script {
+namespace mozjs {
+namespace util {
+std::vector<StackFrame> GetStackTrace(JSContext* context, int max_frames) {
+ JS::StackDescription* stack_description =
+ JS::DescribeStack(context, max_frames);
+ if (max_frames == 0) {
+ max_frames = static_cast<int>(stack_description->nframes);
+ } else {
+ max_frames =
+ std::min(max_frames, static_cast<int>(stack_description->nframes));
+ }
+ JS::FrameDescription* stack_trace = stack_description->frames;
+ std::vector<StackFrame> stack_frames(max_frames);
+ for (int i = 0; i < max_frames; ++i) {
+ StackFrame sf;
+ sf.line_number = stack_trace[i].lineno;
+ sf.column_number = 0;
+ sf.function_name = "global code";
+ if (stack_trace[i].fun) {
+ JS::RootedString rooted_string(context,
+ JS_GetFunctionId(stack_trace[i].fun));
+ JS::RootedValue rooted_value(context, STRING_TO_JSVAL(rooted_string));
+ MozjsExceptionState exception_state(context);
+ FromJSValue(context, rooted_value, kNoConversionFlags, &exception_state,
+ &sf.function_name);
+ }
+ if (stack_trace[i].script) {
+ sf.source_url = stack_trace[i].script->filename();
+ }
+ stack_frames[i] = sf;
+ }
+ JS::FreeStackDescription(context, stack_description);
+ return stack_frames;
+}
+} // namespace util
+} // namespace mozjs
+} // namespace script
+} // namespace cobalt
diff --git a/src/cobalt/script/mozjs/util/exception_helpers.h b/src/cobalt/script/mozjs/util/exception_helpers.h
new file mode 100644
index 0000000..75dff27
--- /dev/null
+++ b/src/cobalt/script/mozjs/util/exception_helpers.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2016 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.
+ */
+#ifndef COBALT_SCRIPT_MOZJS_UTIL_EXCEPTION_HELPERS_H_
+#define COBALT_SCRIPT_MOZJS_UTIL_EXCEPTION_HELPERS_H_
+
+#include <vector>
+
+#include "cobalt/script/stack_frame.h"
+#include "third_party/mozjs/js/src/jsapi.h"
+
+namespace cobalt {
+namespace script {
+namespace mozjs {
+namespace util {
+std::vector<StackFrame> GetStackTrace(JSContext* context, int max_frames);
+} // namespace util
+} // namespace mozjs
+} // namespace script
+} // namespace cobalt
+#endif // COBALT_SCRIPT_MOZJS_UTIL_EXCEPTION_HELPERS_H_
diff --git a/src/cobalt/script/mozjs/wrapper_private.cc b/src/cobalt/script/mozjs/wrapper_private.cc
index b7b3443..e129678 100644
--- a/src/cobalt/script/mozjs/wrapper_private.cc
+++ b/src/cobalt/script/mozjs/wrapper_private.cc
@@ -39,11 +39,13 @@
}
// static
-void WrapperPrivate::AddPrivateData(JS::HandleObject wrapper_proxy,
+void WrapperPrivate::AddPrivateData(JSContext* context,
+ JS::HandleObject wrapper_proxy,
const scoped_refptr<Wrappable>& wrappable) {
DCHECK(js::IsProxy(wrapper_proxy));
WrapperPrivate* private_data = new WrapperPrivate(wrappable, wrapper_proxy);
- JSObject* target_object = js::GetProxyTargetObject(wrapper_proxy);
+ JS::RootedObject target_object(context,
+ js::GetProxyTargetObject(wrapper_proxy));
JS_SetPrivate(target_object, private_data);
DCHECK_EQ(JS_GetPrivate(target_object), private_data);
}
@@ -114,6 +116,8 @@
DCHECK(js::IsProxy(wrapper_proxy));
}
+WrapperPrivate::~WrapperPrivate() { wrapper_proxy_ = NULL; }
+
} // namespace mozjs
} // namespace script
} // namespace cobalt
diff --git a/src/cobalt/script/mozjs/wrapper_private.h b/src/cobalt/script/mozjs/wrapper_private.h
index 9bb4219..e80ec75 100644
--- a/src/cobalt/script/mozjs/wrapper_private.h
+++ b/src/cobalt/script/mozjs/wrapper_private.h
@@ -47,7 +47,7 @@
void RemoveReferencedObject(JS::HandleObject referee);
// Create a new WrapperPrivate instance and associate it with the wrapper.
- static void AddPrivateData(JS::HandleObject wrapper_proxy,
+ static void AddPrivateData(JSContext* context, JS::HandleObject wrapper_proxy,
const scoped_refptr<Wrappable>& wrappable);
// Get the WrapperPrivate associated with the given Wrappable. A new JSObject
@@ -78,6 +78,7 @@
typedef ScopedVector<JS::Heap<JSObject*> > ReferencedObjectVector;
WrapperPrivate(const scoped_refptr<Wrappable>& wrappable,
JS::HandleObject wrapper_proxy);
+ ~WrapperPrivate();
scoped_refptr<Wrappable> wrappable_;
JS::Heap<JSObject*> wrapper_proxy_;
diff --git a/src/cobalt/webdriver/window_driver.cc b/src/cobalt/webdriver/window_driver.cc
index cb14bb9..b896311 100644
--- a/src/cobalt/webdriver/window_driver.cc
+++ b/src/cobalt/webdriver/window_driver.cc
@@ -164,7 +164,13 @@
get_global_object_proxy_(get_global_object_proxy_function),
window_message_loop_(message_loop),
element_driver_map_deleter_(&element_drivers_),
- next_element_id_(0) {}
+ next_element_id_(0) {
+ // The WindowDriver may have been created on some arbitrary thread (i.e. the
+ // thread that owns the Window). Detach the thread checker so it can be
+ // re-bound to the next thread that calls a webdriver API, which should be
+ // the WebDriver thread.
+ thread_checker_.DetachFromThread();
+}
WindowDriver::~WindowDriver() {
DCHECK(thread_checker_.CalledOnValidThread());
diff --git a/src/codereview.settings b/src/codereview.settings
deleted file mode 100644
index a4b341a..0000000
--- a/src/codereview.settings
+++ /dev/null
@@ -1,4 +0,0 @@
-# This file is used by gcl to get repository specific information.
-GERRIT_HOST: lbshell-internal-review.googlesource.com
-GERRIT_AUTODETECT_BRANCH: true
-CODE_REVIEW_SERVER: lbshell-internal-review.googlesource.com
diff --git a/src/glimp/codereview.settings b/src/glimp/codereview.settings
deleted file mode 100644
index a4b341a..0000000
--- a/src/glimp/codereview.settings
+++ /dev/null
@@ -1,4 +0,0 @@
-# This file is used by gcl to get repository specific information.
-GERRIT_HOST: lbshell-internal-review.googlesource.com
-GERRIT_AUTODETECT_BRANCH: true
-CODE_REVIEW_SERVER: lbshell-internal-review.googlesource.com
diff --git a/src/glimp/gles/pixel_format.cc b/src/glimp/gles/pixel_format.cc
index 5c0f76b..ac1672e 100644
--- a/src/glimp/gles/pixel_format.cc
+++ b/src/glimp/gles/pixel_format.cc
@@ -36,6 +36,14 @@
int BytesPerPixel(PixelFormat format) {
SB_COMPILE_ASSERT(SB_ARRAY_SIZE(kBytesPerPixel) == kPixelFormatNumFormats,
kBytesPerPixel_has_entries_for_each_enum_PixelFormat);
+ if (kPixelFormatInvalid == format) {
+ return 0; // Invalid formats have 0 bytes per pixel.
+ }
+
+ if (format < 0 || format >= kPixelFormatNumFormats) {
+ SB_DCHECK(false) << "Invalid PixelFormat: " << format;
+ return 0;
+ }
return kBytesPerPixel[format];
}
diff --git a/src/googleurl/codereview.settings b/src/googleurl/codereview.settings
deleted file mode 100644
index a4b341a..0000000
--- a/src/googleurl/codereview.settings
+++ /dev/null
@@ -1,4 +0,0 @@
-# This file is used by gcl to get repository specific information.
-GERRIT_HOST: lbshell-internal-review.googlesource.com
-GERRIT_AUTODETECT_BRANCH: true
-CODE_REVIEW_SERVER: lbshell-internal-review.googlesource.com
diff --git a/src/media/base/sbplayer_pipeline.cc b/src/media/base/sbplayer_pipeline.cc
index 5a9ce70..7248c25 100644
--- a/src/media/base/sbplayer_pipeline.cc
+++ b/src/media/base/sbplayer_pipeline.cc
@@ -649,7 +649,7 @@
bool is_encrypted = IsEncrypted(stream);
SbDrmSampleInfo drm_info;
- if (is_encrypted) {
+ if (is_encrypted && !buffer->IsEndOfStream()) {
FillDrmSampleInfo(buffer, &drm_info);
}
diff --git a/src/media/base/shell_video_frame_provider.cc b/src/media/base/shell_video_frame_provider.cc
index e4910d2..589f886 100644
--- a/src/media/base/shell_video_frame_provider.cc
+++ b/src/media/base/shell_video_frame_provider.cc
@@ -22,9 +22,8 @@
ShellVideoFrameProvider::ShellVideoFrameProvider(
scoped_refptr<VideoFrame> punch_out)
- : punch_out_(punch_out), has_consumed_frames_(false) {
+ : punch_out_(punch_out), has_consumed_frames_(false), dropped_frames_(0) {
#if !defined(__LB_SHELL__FOR_RELEASE__)
- dropped_frames_ = 0;
max_delay_in_microseconds_ = 0;
#endif // !defined(__LB_SHELL__FOR_RELEASE__)
}
@@ -67,24 +66,26 @@
frame_time + kEpsilonInMicroseconds >= media_time.InMicroseconds())
break;
-#if !defined(__LB_SHELL__FOR_RELEASE__)
- const bool kLogFrameDrops ALLOW_UNUSED = false;
if (current_frame_ != frames_[0]) {
++dropped_frames_;
+
+#if !defined(__LB_SHELL__FOR_RELEASE__)
if (media_time.InMicroseconds() - frame_time > max_delay_in_microseconds_)
max_delay_in_microseconds_ = media_time.InMicroseconds() - frame_time;
+ const bool kLogFrameDrops ALLOW_UNUSED = false;
LOG_IF(WARNING, kLogFrameDrops)
<< "dropped one frame with timestamp "
<< frames_[0]->GetTimestamp().InMicroseconds() << " at media time "
<< media_time.InMicroseconds() << " total dropped " << dropped_frames_
<< " frames with a max delay of " << max_delay_in_microseconds_
<< " ms";
- }
#endif // !defined(__LB_SHELL__FOR_RELEASE__)
+ }
if (frames_.size() == 1) {
current_frame_ = frames_[0];
}
+
frames_.erase(frames_.begin());
has_consumed_frames_ = true;
}
@@ -108,6 +109,7 @@
base::AutoLock auto_lock(frames_lock_);
frames_.clear();
current_frame_ = NULL;
+ dropped_frames_ = 0;
}
size_t ShellVideoFrameProvider::GetNumOfFramesCached() const {
@@ -127,4 +129,11 @@
return previous_value;
}
+int ShellVideoFrameProvider::ResetAndReturnDroppedFrames() {
+ base::AutoLock auto_lock(frames_lock_);
+ int dropped_frames = dropped_frames_;
+ dropped_frames_ = 0;
+ return dropped_frames;
+}
+
} // namespace media
diff --git a/src/media/base/shell_video_frame_provider.h b/src/media/base/shell_video_frame_provider.h
index a26a2db..47ab8da 100644
--- a/src/media/base/shell_video_frame_provider.h
+++ b/src/media/base/shell_video_frame_provider.h
@@ -64,6 +64,9 @@
// queue since the last time this was called.
bool QueryAndResetHasConsumedFrames();
+ // Return the value of |dropped_frames_| and reset it to 0.
+ int ResetAndReturnDroppedFrames();
+
private:
base::TimeDelta GetMediaTime_Locked() const;
@@ -74,9 +77,9 @@
std::vector<scoped_refptr<VideoFrame> > frames_;
scoped_refptr<VideoFrame> current_frame_;
bool has_consumed_frames_;
+ int dropped_frames_;
#if !defined(__LB_SHELL__FOR_RELEASE__)
- int dropped_frames_;
int max_delay_in_microseconds_;
#endif // !defined(__LB_SHELL__FOR_RELEASE__)
diff --git a/src/media/filters/shell_demuxer.cc b/src/media/filters/shell_demuxer.cc
index 3da9455..6671985 100644
--- a/src/media/filters/shell_demuxer.cc
+++ b/src/media/filters/shell_demuxer.cc
@@ -232,27 +232,33 @@
base::Bind(&ShellDemuxer::ParseConfigDone, this, status_cb));
}
-bool ShellDemuxer::ParseConfigBlocking(const PipelineStatusCB& status_cb) {
+PipelineStatus ShellDemuxer::ParseConfigBlocking(
+ const PipelineStatusCB& status_cb) {
DCHECK(blocking_thread_.message_loop_proxy()->BelongsToCurrentThread());
DCHECK(!parser_);
// construct stream parser with error callback
- parser_ = ShellParser::Construct(reader_, status_cb);
+ PipelineStatus status = ShellParser::Construct(reader_, &parser_);
// if we can't construct a parser for this stream it's a fatal error, return
// false so ParseConfigDone will notify the caller to Initialize() via
// status_cb.
- if (!parser_) {
- return false;
+ if (!parser_ || status != PIPELINE_OK) {
+ DCHECK(!parser_);
+ DCHECK_NE(status, PIPELINE_OK);
+ if (status == PIPELINE_OK) {
+ status = DEMUXER_ERROR_COULD_NOT_PARSE;
+ }
+ return status;
}
// instruct the parser to extract audio and video config from the file
if (!parser_->ParseConfig()) {
- return false;
+ return DEMUXER_ERROR_COULD_NOT_PARSE;
}
// make sure we got a valid and complete configuration
if (!parser_->IsConfigComplete()) {
- return false;
+ return DEMUXER_ERROR_COULD_NOT_PARSE;
}
// IsConfigComplete() should guarantee we know the duration
@@ -265,18 +271,19 @@
}
// successful parse of config data, inform the nonblocking demuxer thread
- return true;
+ DCHECK_EQ(status, PIPELINE_OK);
+ return PIPELINE_OK;
}
void ShellDemuxer::ParseConfigDone(const PipelineStatusCB& status_cb,
- bool result) {
+ PipelineStatus status) {
DCHECK(MessageLoopBelongsToCurrentThread());
// if the blocking parser thread cannot parse config we're done.
- if (!result) {
- status_cb.Run(DEMUXER_ERROR_COULD_NOT_PARSE);
+ if (status != PIPELINE_OK) {
+ status_cb.Run(status);
return;
}
-
+ DCHECK(parser_);
// start downloading data
Request(DemuxerStream::AUDIO);
diff --git a/src/media/filters/shell_demuxer.h b/src/media/filters/shell_demuxer.h
index c49c28e..886f7fc 100644
--- a/src/media/filters/shell_demuxer.h
+++ b/src/media/filters/shell_demuxer.h
@@ -121,14 +121,15 @@
void BufferAllocated(scoped_refptr<DecoderBuffer> buffer);
private:
- void ParseConfigDone(const PipelineStatusCB& status_cb, bool result);
+ void ParseConfigDone(const PipelineStatusCB& status_cb,
+ PipelineStatus status);
void DataSourceStopped(const base::Closure& callback);
// methods that perform blocking I/O, and are therefore run on the
// blocking_thread_
// download enough of the stream to parse the configuration. returns
// false on error.
- bool ParseConfigBlocking(const PipelineStatusCB& status_cb);
+ PipelineStatus ParseConfigBlocking(const PipelineStatusCB& status_cb);
void RequestTask(DemuxerStream::Type type);
void DownloadTask(scoped_refptr<DecoderBuffer> buffer);
void IssueNextRequestTask();
diff --git a/src/media/filters/shell_flv_parser.cc b/src/media/filters/shell_flv_parser.cc
index 5d517ad..4492a49 100644
--- a/src/media/filters/shell_flv_parser.cc
+++ b/src/media/filters/shell_flv_parser.cc
@@ -70,28 +70,33 @@
static const int kAMF0NumberLength = 9;
// static
-scoped_refptr<ShellParser> ShellFLVParser::Construct(
+PipelineStatus ShellFLVParser::Construct(
scoped_refptr<ShellDataSourceReader> reader,
const uint8* construction_header,
- const PipelineStatusCB& status_cb) {
+ scoped_refptr<ShellParser>* parser) {
+ DCHECK(parser);
+ *parser = NULL;
+
// look for "FLV" string at top of file, mask off LSB
uint32 FLV = endian_util::load_uint32_big_endian(construction_header) >> 8;
if (FLV != kFLV) {
- return NULL;
+ // Not an flv.
+ return DEMUXER_ERROR_COULD_NOT_PARSE;
}
// Check for availability of both an audio and video stream. Audio stream is
// third bit, video stream is first bit in 5th byte of file header
if ((construction_header[4] & 0x05) != 0x05) {
- status_cb.Run(DEMUXER_ERROR_NO_SUPPORTED_STREAMS);
- return NULL;
+ return DEMUXER_ERROR_NO_SUPPORTED_STREAMS;
}
// offset of first data tag in stream is next 4 bytes
uint32 data_offset =
endian_util::load_uint32_big_endian(construction_header + 5);
// add four bytes to skip over PreviousTagSize0
data_offset += 4;
- // construct and return an FLV parser
- return scoped_refptr<ShellParser>(new ShellFLVParser(reader, data_offset));
+
+ // construct an FLV parser
+ *parser = new ShellFLVParser(reader, data_offset);
+ return PIPELINE_OK;
}
ShellFLVParser::ShellFLVParser(scoped_refptr<ShellDataSourceReader> reader,
diff --git a/src/media/filters/shell_flv_parser.h b/src/media/filters/shell_flv_parser.h
index 992bee9..1f512c0 100644
--- a/src/media/filters/shell_flv_parser.h
+++ b/src/media/filters/shell_flv_parser.h
@@ -28,12 +28,12 @@
class ShellFLVParser : public ShellAVCParser {
public:
// Attempts to make sense of the provided bytes of the top of a file as an
- // flv, and if it does make sense returns a ShellFLVParser initialized with
- // some basic state. If it doesn't make sense this returns NULL.
- static scoped_refptr<ShellParser> Construct(
- scoped_refptr<ShellDataSourceReader> reader,
- const uint8* construction_header,
- const PipelineStatusCB& status_cb);
+ // flv, and if it does make sense returns PIPELINE_OK and |*parser| contains a
+ // ShellFLVParser initialized with some basic state. If it doesn't make sense
+ // this returns an error status and |*parser| contains NULL.
+ static PipelineStatus Construct(scoped_refptr<ShellDataSourceReader> reader,
+ const uint8* construction_header,
+ scoped_refptr<ShellParser>* parser);
ShellFLVParser(scoped_refptr<ShellDataSourceReader> reader,
uint32 tag_start_offset);
virtual ~ShellFLVParser();
diff --git a/src/media/filters/shell_mp4_parser.cc b/src/media/filters/shell_mp4_parser.cc
index 20ea082..0360858 100644
--- a/src/media/filters/shell_mp4_parser.cc
+++ b/src/media/filters/shell_mp4_parser.cc
@@ -72,34 +72,36 @@
static const int kMapTableAtomCacheEntries_ctts = 51543 / kEntrySize_ctts;
// static
-scoped_refptr<ShellParser> ShellMP4Parser::Construct(
+PipelineStatus ShellMP4Parser::Construct(
scoped_refptr<ShellDataSourceReader> reader,
const uint8* construction_header,
- const PipelineStatusCB& status_cb) {
+ scoped_refptr<ShellParser>* parser) {
+ DCHECK(parser);
+ *parser = NULL;
+
// detect mp4 stream by looking for ftyp atom at top of file
uint32 ftyp = endian_util::load_uint32_big_endian(construction_header + 4);
if (ftyp != kAtomType_ftyp) {
// not an mp4
- return NULL;
+ return DEMUXER_ERROR_COULD_NOT_PARSE;
}
// first 4 bytes will be the size of the ftyp atom
uint32 ftyp_atom_size =
endian_util::load_uint32_big_endian(construction_header);
if (ftyp_atom_size < kAtomMinSize) {
- status_cb.Run(DEMUXER_ERROR_COULD_NOT_PARSE);
- return NULL;
+ return DEMUXER_ERROR_COULD_NOT_PARSE;
}
- // construct and return new mp4 parser
- return scoped_refptr<ShellParser>(new ShellMP4Parser(reader, ftyp_atom_size));
+ // construct new mp4 parser
+ *parser = new ShellMP4Parser(reader, ftyp_atom_size);
+ return PIPELINE_OK;
}
ShellMP4Parser::ShellMP4Parser(scoped_refptr<ShellDataSourceReader> reader,
uint32 ftyp_atom_size)
: ShellAVCParser(reader),
- atom_offset_(ftyp_atom_size) // start at next atom, skipping over ftyp
- ,
+ atom_offset_(ftyp_atom_size), // start at next atom, skipping over ftyp
current_trak_is_video_(false),
current_trak_is_audio_(false),
current_trak_time_scale_(0),
diff --git a/src/media/filters/shell_mp4_parser.h b/src/media/filters/shell_mp4_parser.h
index a890c2c..bf7ea68 100644
--- a/src/media/filters/shell_mp4_parser.h
+++ b/src/media/filters/shell_mp4_parser.h
@@ -67,13 +67,13 @@
class ShellMP4Parser : public ShellAVCParser {
public:
- // attempts to make sense of the provided bytes of the top of a file as an
- // mp4, and if it does make sense returns a ShellMP4Parser initialized with
- // some basic state. If it doesn't make sense this returns NULL
- static scoped_refptr<ShellParser> Construct(
- scoped_refptr<ShellDataSourceReader> reader,
- const uint8* construction_header,
- const PipelineStatusCB& status_cb);
+ // Attempts to make sense of the provided bytes of the top of a file as an
+ // flv, and if it does make sense returns PIPELINE_OK and |*parser| contains a
+ // ShellMP4Parser initialized with some basic state. If it doesn't make sense
+ // this returns an error status and |*parser| contains NULL.
+ static PipelineStatus Construct(scoped_refptr<ShellDataSourceReader> reader,
+ const uint8* construction_header,
+ scoped_refptr<ShellParser>* parser);
ShellMP4Parser(scoped_refptr<ShellDataSourceReader> reader,
uint32 ftyp_atom_size);
virtual ~ShellMP4Parser();
diff --git a/src/media/filters/shell_parser.cc b/src/media/filters/shell_parser.cc
index b8b5c1c..f1d4958 100644
--- a/src/media/filters/shell_parser.cc
+++ b/src/media/filters/shell_parser.cc
@@ -16,6 +16,7 @@
#include "media/filters/shell_parser.h"
+#include "base/logging.h"
#include "media/filters/shell_flv_parser.h"
#include "media/filters/shell_mp4_parser.h"
@@ -27,33 +28,27 @@
const int ShellParser::kInitialHeaderSize = 9;
// static
-scoped_refptr<ShellParser> ShellParser::Construct(
+PipelineStatus ShellParser::Construct(
scoped_refptr<ShellDataSourceReader> reader,
- const PipelineStatusCB& status_cb) {
- scoped_refptr<ShellParser> parser;
+ scoped_refptr<ShellParser>* parser) {
+ DCHECK(parser);
+ *parser = NULL;
// download first 16 bytes of stream to determine file type and extract basic
// container-specific stream configuration information
uint8 header[kInitialHeaderSize];
int bytes_read = reader->BlockingRead(0, kInitialHeaderSize, header);
if (bytes_read != kInitialHeaderSize) {
- status_cb.Run(DEMUXER_ERROR_COULD_NOT_OPEN);
- return NULL;
+ return DEMUXER_ERROR_COULD_NOT_PARSE;
}
// attempt to construct mp4 parser from this header
- parser = ShellMP4Parser::Construct(reader, header, status_cb);
+ PipelineStatus status = ShellMP4Parser::Construct(reader, header, parser);
+ if (status == PIPELINE_OK) {
+ return status;
+ }
// ok, attempt FLV
- if (!parser) {
- parser = ShellFLVParser::Construct(reader, header, status_cb);
- }
- // no additional supported container formats, set error and return
- if (!parser) {
- status_cb.Run(DEMUXER_ERROR_NO_SUPPORTED_STREAMS);
- return NULL;
- }
-
- return parser;
+ return ShellFLVParser::Construct(reader, header, parser);
}
ShellParser::ShellParser(scoped_refptr<ShellDataSourceReader> reader)
diff --git a/src/media/filters/shell_parser.h b/src/media/filters/shell_parser.h
index 057cbae..6d349b0 100644
--- a/src/media/filters/shell_parser.h
+++ b/src/media/filters/shell_parser.h
@@ -32,10 +32,10 @@
class ShellParser : public base::RefCountedThreadSafe<ShellParser> {
public:
static const int kInitialHeaderSize;
- // Determine stream type, construct appropriate parser object, and return.
- static scoped_refptr<ShellParser> Construct(
- scoped_refptr<ShellDataSourceReader> reader,
- const PipelineStatusCB& status_cb);
+ // Determine stream type, construct appropriate parser object, and returns
+ // PIPELINE_OK on success or error code.
+ static PipelineStatus Construct(scoped_refptr<ShellDataSourceReader> reader,
+ scoped_refptr<ShellParser>* parser);
explicit ShellParser(scoped_refptr<ShellDataSourceReader> reader);
// Seek through the file looking for audio and video configuration info,
diff --git a/src/media/filters/video_renderer_base.cc b/src/media/filters/video_renderer_base.cc
index f1fa6fc..80d1f3d 100644
--- a/src/media/filters/video_renderer_base.cc
+++ b/src/media/filters/video_renderer_base.cc
@@ -300,14 +300,17 @@
uint32 frames_dropped = 0;
for (;;) {
- if (frames_dropped > 0) {
#if defined(__LB_SHELL__) || defined(COBALT)
+ frames_dropped =
+ static_cast<uint32>(frame_provider_->ResetAndReturnDroppedFrames());
+ if (frames_dropped > 0) {
SCOPED_MEDIA_STATISTICS(STAT_TYPE_VIDEO_FRAME_DROP);
+ }
#endif // defined(__LB_SHELL__) || defined(COBALT)
+ if (frames_dropped > 0) {
PipelineStatistics statistics;
statistics.video_frames_dropped = frames_dropped;
statistics_cb_.Run(statistics);
-
frames_dropped = 0;
}
diff --git a/src/nb/codereview.settings b/src/nb/codereview.settings
deleted file mode 100644
index a4b341a..0000000
--- a/src/nb/codereview.settings
+++ /dev/null
@@ -1,4 +0,0 @@
-# This file is used by gcl to get repository specific information.
-GERRIT_HOST: lbshell-internal-review.googlesource.com
-GERRIT_AUTODETECT_BRANCH: true
-CODE_REVIEW_SERVER: lbshell-internal-review.googlesource.com
diff --git a/src/nb/memory_pool.cc b/src/nb/memory_pool.cc
index a420420..840042c 100644
--- a/src/nb/memory_pool.cc
+++ b/src/nb/memory_pool.cc
@@ -20,13 +20,22 @@
namespace nb {
-MemoryPool::MemoryPool(void* buffer, std::size_t size, bool thread_safe)
+MemoryPool::MemoryPool(void* buffer,
+ std::size_t size,
+ bool thread_safe,
+ bool verify_full_capacity)
: no_free_allocator_(buffer, size),
reuse_allocator_(
scoped_ptr<Allocator>(new ReuseAllocator(&no_free_allocator_)),
thread_safe) {
SB_DCHECK(buffer);
SB_DCHECK(size != 0U);
+
+ if (verify_full_capacity) {
+ void* p = Allocate(size);
+ SB_DCHECK(p);
+ Free(p);
+ }
}
void MemoryPool::PrintAllocations() const {
diff --git a/src/nb/memory_pool.h b/src/nb/memory_pool.h
index c6245b9..cef03db 100644
--- a/src/nb/memory_pool.h
+++ b/src/nb/memory_pool.h
@@ -29,7 +29,22 @@
// as necessary.
class MemoryPool : public Allocator {
public:
- MemoryPool(void* buffer, std::size_t size, bool thread_safe);
+ // When |verify_full_capacity| is true, the ctor tries to allocate the whole
+ // budget and free it immediately. This can:
+ // 1. Ensure the |size| is accurate after accounting for all implicit
+ // alignment enforced by the underlying allocators.
+ // 2. The |reuse_allocator_| contains a free block of the whole budget. As
+ // the |reuse_allocator_| doesn't support extending of free block, an
+ // allocation that is larger than the both biggest free block in the
+ // |reuse_allocator_| and the remaining memory inside the
+ // |no_free_allocator_| will fail even if the combination of both can
+ // fulfill the allocation.
+ // Note that when |verify_full_capacity| is true, GetHighWaterMark() always
+ // return the budget, which makes memory usage tracking useless.
+ MemoryPool(void* buffer,
+ std::size_t size,
+ bool thread_safe,
+ bool verify_full_capacity = false);
void* Allocate(std::size_t size) { return reuse_allocator_.Allocate(size); }
void* Allocate(std::size_t size, std::size_t alignment) {
diff --git a/src/nb/reuse_allocator.cc b/src/nb/reuse_allocator.cc
index 8fc07cf..61a40a6 100644
--- a/src/nb/reuse_allocator.cc
+++ b/src/nb/reuse_allocator.cc
@@ -98,7 +98,7 @@
}
void* ReuseAllocator::Allocate(std::size_t size) {
- return Allocate(size, 0);
+ return Allocate(size, 1);
}
void* ReuseAllocator::AllocateForAlignment(std::size_t size,
@@ -107,6 +107,10 @@
}
void* ReuseAllocator::Allocate(std::size_t size, std::size_t alignment) {
+ if (alignment == 0) {
+ alignment = 1;
+ }
+
// Try to satisfy request from free list.
// First look for a block that is appropriately aligned.
// If we can't, look for a block that is big enough that we can
diff --git a/src/starboard/audio_sink.h b/src/starboard/audio_sink.h
index efedf24..59f507b 100644
--- a/src/starboard/audio_sink.h
+++ b/src/starboard/audio_sink.h
@@ -42,6 +42,14 @@
// audio frame buffer passed to SbAudioSinkCreate as |frame_buffers|. As
// |frame_buffers| is a circular buffer, |offset_in_frames| can be used to
// calculate the number of continuous frames towards the end of the buffer.
+// The audio sink can play the frames only when |is_playing| is true. It should
+// pause the playback when |is_playing| is false.
+// The audio sink may cache certain amount of audio frames before start
+// playback. It will start playback immediately when |is_eos_reached| is true
+// even if the amount of cached audio frames are not enough as no more frames
+// will be appended into the buffer when |is_eos_reached| is true.
+// It is possible for a host to set |is_eos_reached| to false after setting it
+// to true, usually this is caused by a seek.
// All parameters except |context| cannot be NULL.
// Note that this function only reports the status of the source, it doesn't
// remove audio data from the source frame buffer.
diff --git a/src/starboard/codereview.settings b/src/starboard/codereview.settings
deleted file mode 100644
index a4b341a..0000000
--- a/src/starboard/codereview.settings
+++ /dev/null
@@ -1,4 +0,0 @@
-# This file is used by gcl to get repository specific information.
-GERRIT_HOST: lbshell-internal-review.googlesource.com
-GERRIT_AUTODETECT_BRANCH: true
-CODE_REVIEW_SERVER: lbshell-internal-review.googlesource.com
diff --git a/src/starboard/configuration.h b/src/starboard/configuration.h
index a106891..cff8fa8 100644
--- a/src/starboard/configuration.h
+++ b/src/starboard/configuration.h
@@ -58,7 +58,8 @@
#define SB_IS(SB_FEATURE) (defined(SB_IS_##SB_FEATURE) && SB_IS_##SB_FEATURE)
// Determines at compile-time whether this platform has a quirk.
-#define SB_HAS_QUIRK(SB_FEATURE) (defined(SB_HAS_QUIRK_##SB_FEATURE) && SB_HAS_QUIRK_##SB_FEATURE)
+#define SB_HAS_QUIRK(SB_FEATURE) \
+ (defined(SB_HAS_QUIRK_##SB_FEATURE) && SB_HAS_QUIRK_##SB_FEATURE)
// Determines at compile-time if this platform implements a given Starboard API
// version number (or above).
@@ -335,10 +336,6 @@
#error "Your platform must define SB_MAX_THREAD_NAME_LENGTH."
#endif
-#if !SB_HAS(DECODER) && !SB_HAS(PLAYER)
-#error "Your platform must have either a decoder or a player (or both)."
-#endif
-
#if SB_HAS(PLAYER)
#if !SB_IS(PLAYER_COMPOSITED) && !SB_IS(PLAYER_PUNCHED_OUT) && \
!SB_IS(PLAYER_PRODUCING_TEXTURE)
@@ -356,17 +353,15 @@
SB_IS(PLAYER_PRODUCING_TEXTURE)
#error "Your player can't have a composition method if it doesn't exist."
#endif
-
-#if !SB_HAS(DECODER)
-#error "Your platform must have either a decoder or a player."
-#endif
#endif // SB_HAS(PLAYER)
-#if (SB_HAS(MANY_CORES) && \
- (SB_HAS(2_CORES) || SB_HAS(4_CORES) || SB_HAS(6_CORES))) || \
- (SB_HAS(2_CORES) && (SB_HAS(4_CORES) || SB_HAS(6_CORES))) || \
+#if (SB_HAS(MANY_CORES) && (SB_HAS(1_CORE) || SB_HAS(2_CORES) || \
+ SB_HAS(4_CORES) || SB_HAS(6_CORES))) || \
+ (SB_HAS(1_CORE) && \
+ (SB_HAS(2_CORES) || SB_HAS(4_CORES) || SB_HAS(6_CORES))) || \
+ (SB_HAS(2_CORES) && (SB_HAS(4_CORES) || SB_HAS(6_CORES))) || \
(SB_HAS(4_CORES) && SB_HAS(6_CORES))
-#error "Only one of SB_HAS_{MANY, 2, 4, 6}_CORES can be defined per platform."
+#error "Only one SB_HAS_{MANY, 1, 2, 4, 6}_CORE[S] can be defined per platform."
#endif
#if !defined(SB_PREFERRED_RGBA_BYTE_ORDER)
diff --git a/src/starboard/event.h b/src/starboard/event.h
index c9f5614..5c1db49 100644
--- a/src/starboard/event.h
+++ b/src/starboard/event.h
@@ -78,6 +78,19 @@
// No data argument.
kSbEventTypeVerticalSync,
+ // The platform has detected a network disconnection. The platform should make
+ // a best effort to send an event of this type when the network disconnects,
+ // but there are likely to be cases where the platform cannot detect the
+ // disconnection (e.g. if the connection is via a powered hub which becomes
+ // disconnected), so the current network state cannot always be inferred from
+ // the sequence of Connect/Disconnect events.
+ kSbEventTypeNetworkDisconnect,
+
+ // The platform has detected a network connection. This event may be sent at
+ // application start-up, and should always be sent if the network reconnects
+ // since a disconnection event was sent.
+ kSbEventTypeNetworkConnect,
+
// An event type reserved for scheduled callbacks. It will only be sent in
// response to an application call to SbEventSchedule(), and it will call the
// callback directly, so SbEventHandle should never receive this event
diff --git a/src/starboard/linux/shared/configuration_public.h b/src/starboard/linux/shared/configuration_public.h
index 4a161d9..624909f 100644
--- a/src/starboard/linux/shared/configuration_public.h
+++ b/src/starboard/linux/shared/configuration_public.h
@@ -234,18 +234,12 @@
// --- Media Configuration ---------------------------------------------------
-// Specifies whether this platform has support for direct access to a decoder
-// for at least H.264/AAC. The decoder is likely to be faster-than-realtime, and
-// it is up to the client to retain decoded frames and display them synchronized
-// with the audio. The decoder must be wired up to the DRM system such that it
-// accepts encrypted samples.
-#define SB_HAS_DECODER 0
-
-// Specifies whether this platform has support for a decrypting elementary
-// stream player for at least AES128-CTR/H.264/AAC. A player is responsible for
-// ingesting an audio and video elementary stream, optionally-encrypted, and
-// ultimately producing synchronized audio/video. If a player is defined, it
-// must choose one of the supported composition methods below.
+// Specifies whether this platform has support for a possibly-decrypting
+// elementary stream player for at least H.264/AAC (and AES-128-CTR, if
+// decrypting). A player is responsible for ingesting an audio and video
+// elementary stream, optionally-encrypted, and ultimately producing
+// synchronized audio/video. If a player is defined, it must choose one of the
+// supported composition methods below.
#define SB_HAS_PLAYER 1
// Specifies whether this platform's player will produce an OpenGL texture that
diff --git a/src/starboard/linux/x64directfb/starboard_platform.gyp b/src/starboard/linux/x64directfb/starboard_platform.gyp
index 279c8d9..e692647 100644
--- a/src/starboard/linux/x64directfb/starboard_platform.gyp
+++ b/src/starboard/linux/x64directfb/starboard_platform.gyp
@@ -150,8 +150,6 @@
'<(DEPTH)/starboard/shared/nouser/user_get_property.cc',
'<(DEPTH)/starboard/shared/nouser/user_get_signed_in.cc',
'<(DEPTH)/starboard/shared/nouser/user_internal.cc',
- '<(DEPTH)/starboard/shared/nouser/user_is_age_restricted.cc',
- '<(DEPTH)/starboard/shared/nouser/user_start_sign_in.cc',
'<(DEPTH)/starboard/shared/posix/directory_create.cc',
'<(DEPTH)/starboard/shared/posix/file_can_open.cc',
'<(DEPTH)/starboard/shared/posix/file_close.cc',
@@ -301,6 +299,7 @@
'<(DEPTH)/starboard/shared/stub/drm_update_session.cc',
'<(DEPTH)/starboard/shared/stub/media_is_supported.cc',
'<(DEPTH)/starboard/shared/stub/system_clear_platform_error.cc',
+ '<(DEPTH)/starboard/shared/stub/system_hide_splash_screen.cc',
'<(DEPTH)/starboard/shared/stub/system_raise_platform_error.cc',
],
'include_dirs': [
diff --git a/src/starboard/linux/x64x11/configuration_public.h b/src/starboard/linux/x64x11/configuration_public.h
index f11107c..2291350 100644
--- a/src/starboard/linux/x64x11/configuration_public.h
+++ b/src/starboard/linux/x64x11/configuration_public.h
@@ -83,6 +83,9 @@
// wildly varying number of cores.
#define SB_HAS_MANY_CORES 1
+// Whether the current platform is expected to have exactly 1 core.
+#define SB_HAS_1_CORE 0
+
// Whether the current platform is expected to have exactly 2 cores.
#define SB_HAS_2_CORES 0
diff --git a/src/starboard/linux/x64x11/starboard_platform.gyp b/src/starboard/linux/x64x11/starboard_platform.gyp
index 46ea9aa..1609af2 100644
--- a/src/starboard/linux/x64x11/starboard_platform.gyp
+++ b/src/starboard/linux/x64x11/starboard_platform.gyp
@@ -113,8 +113,6 @@
'<(DEPTH)/starboard/shared/nouser/user_get_property.cc',
'<(DEPTH)/starboard/shared/nouser/user_get_signed_in.cc',
'<(DEPTH)/starboard/shared/nouser/user_internal.cc',
- '<(DEPTH)/starboard/shared/nouser/user_is_age_restricted.cc',
- '<(DEPTH)/starboard/shared/nouser/user_start_sign_in.cc',
'<(DEPTH)/starboard/shared/posix/directory_create.cc',
'<(DEPTH)/starboard/shared/posix/file_can_open.cc',
'<(DEPTH)/starboard/shared/posix/file_close.cc',
@@ -262,6 +260,7 @@
'<(DEPTH)/starboard/shared/stub/drm_update_session.cc',
'<(DEPTH)/starboard/shared/stub/media_is_supported.cc',
'<(DEPTH)/starboard/shared/stub/system_clear_platform_error.cc',
+ '<(DEPTH)/starboard/shared/stub/system_hide_splash_screen.cc',
'<(DEPTH)/starboard/shared/stub/system_raise_platform_error.cc',
'<(DEPTH)/starboard/shared/x11/application_x11.cc',
'<(DEPTH)/starboard/shared/x11/window_create.cc',
diff --git a/src/starboard/log.h b/src/starboard/log.h
index 5f3aa9f..3693925 100644
--- a/src/starboard/log.h
+++ b/src/starboard/log.h
@@ -141,6 +141,7 @@
const SbLogPriority SB_LOG_WARNING = kSbLogPriorityWarning;
const SbLogPriority SB_LOG_ERROR = kSbLogPriorityError;
const SbLogPriority SB_LOG_FATAL = kSbLogPriorityFatal;
+const SbLogPriority SB_LOG_0 = SB_LOG_ERROR;
class SB_EXPORT LogMessage {
public:
@@ -185,6 +186,10 @@
::starboard::logging::LogMessage(__FILE__, __LINE__, \
::starboard::logging::SB_LOG_FATAL)
+// Compatibility with base/logging.h which defines ERROR to be 0 to workaround
+// some system header defines that do the same thing.
+#define SB_LOG_MESSAGE_0 SB_LOG_MESSAGE_ERROR
+
#define SB_LOG_STREAM(severity) SB_LOG_MESSAGE_##severity.stream()
#define SB_LAZY_STREAM(stream, condition) \
!(condition) ? (void)0 : ::starboard::logging::LogMessageVoidify() & (stream)
diff --git a/src/starboard/nplb/nplb.gyp b/src/starboard/nplb/nplb.gyp
index 0835148..3761520 100644
--- a/src/starboard/nplb/nplb.gyp
+++ b/src/starboard/nplb/nplb.gyp
@@ -190,6 +190,7 @@
'system_get_stack_test.cc',
'system_get_total_memory_test.cc',
'system_has_capability_test.cc',
+ 'system_hide_splash_screen_test.cc',
'system_is_debugger_attached_test.cc',
'system_sort_test.cc',
'system_symbolize_test.cc',
diff --git a/src/starboard/nplb/system_hide_splash_screen_test.cc b/src/starboard/nplb/system_hide_splash_screen_test.cc
new file mode 100644
index 0000000..a97392e
--- /dev/null
+++ b/src/starboard/nplb/system_hide_splash_screen_test.cc
@@ -0,0 +1,35 @@
+// Copyright 2016 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.
+
+// Here we are not trying to do anything fancy, just to really sanity check that
+// this is hooked up to something.
+
+#include "starboard/system.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace starboard {
+namespace nplb {
+namespace {
+
+TEST(SbSystemHideSplashScreenTest, SunnyDay) {
+ // Function returns no result, and correct execution cannot be determined
+ // programatically, but we should at least be able to call it twice without
+ // crashing.
+ SbSystemHideSplashScreen();
+ SbSystemHideSplashScreen();
+}
+
+} // namespace
+} // namespace nplb
+} // namespace starboard
diff --git a/src/starboard/raspi/1/configuration_public.h b/src/starboard/raspi/1/configuration_public.h
index df2d8bf..3cedc59 100644
--- a/src/starboard/raspi/1/configuration_public.h
+++ b/src/starboard/raspi/1/configuration_public.h
@@ -71,7 +71,10 @@
// Whether the current platform is expected to have many cores (> 6), or a
// wildly varying number of cores.
-#define SB_HAS_MANY_CORES 1
+#define SB_HAS_MANY_CORES 0
+
+// Whether the current platform is expected to have exactly 1 core.
+#define SB_HAS_1_CORE 1
// Whether the current platform is expected to have exactly 2 cores.
#define SB_HAS_2_CORES 0
diff --git a/src/starboard/raspi/1/starboard_platform.gyp b/src/starboard/raspi/1/starboard_platform.gyp
index 1b80d83..7206d0c 100644
--- a/src/starboard/raspi/1/starboard_platform.gyp
+++ b/src/starboard/raspi/1/starboard_platform.gyp
@@ -120,8 +120,6 @@
'<(DEPTH)/starboard/shared/nouser/user_get_property.cc',
'<(DEPTH)/starboard/shared/nouser/user_get_signed_in.cc',
'<(DEPTH)/starboard/shared/nouser/user_internal.cc',
- '<(DEPTH)/starboard/shared/nouser/user_is_age_restricted.cc',
- '<(DEPTH)/starboard/shared/nouser/user_start_sign_in.cc',
'<(DEPTH)/starboard/shared/posix/directory_create.cc',
'<(DEPTH)/starboard/shared/posix/file_can_open.cc',
'<(DEPTH)/starboard/shared/posix/file_close.cc',
@@ -269,6 +267,7 @@
'<(DEPTH)/starboard/shared/stub/drm_update_session.cc',
'<(DEPTH)/starboard/shared/stub/media_is_supported.cc',
'<(DEPTH)/starboard/shared/stub/system_clear_platform_error.cc',
+ '<(DEPTH)/starboard/shared/stub/system_hide_splash_screen.cc',
'<(DEPTH)/starboard/shared/stub/system_raise_platform_error.cc',
],
'defines': [
diff --git a/src/starboard/raspi/shared/configuration_public.h b/src/starboard/raspi/shared/configuration_public.h
index de26224..b7ba3a6 100644
--- a/src/starboard/raspi/shared/configuration_public.h
+++ b/src/starboard/raspi/shared/configuration_public.h
@@ -229,18 +229,12 @@
// --- Media Configuration ---------------------------------------------------
-// Specifies whether this platform has support for direct access to a decoder
-// for at least H.264/AAC. The decoder is likely to be faster-than-realtime, and
-// it is up to the client to retain decoded frames and display them synchronized
-// with the audio. The decoder must be wired up to the DRM system such that it
-// accepts encrypted samples.
-#define SB_HAS_DECODER 0
-
-// Specifies whether this platform has support for a decrypting elementary
-// stream player for at least AES128-CTR/H.264/AAC. A player is responsible for
-// ingesting an audio and video elementary stream, optionally-encrypted, and
-// ultimately producing synchronized audio/video. If a player is defined, it
-// must choose one of the supported composition methods below.
+// Specifies whether this platform has support for a possibly-decrypting
+// elementary stream player for at least H.264/AAC (and AES-128-CTR, if
+// decrypting). A player is responsible for ingesting an audio and video
+// elementary stream, optionally-encrypted, and ultimately producing
+// synchronized audio/video. If a player is defined, it must choose one of the
+// supported composition methods below.
#define SB_HAS_PLAYER 1
// Specifies whether this platform's player will produce an OpenGL texture that
diff --git a/src/starboard/shared/alsa/alsa_audio_sink_type.cc b/src/starboard/shared/alsa/alsa_audio_sink_type.cc
index 5a89222..8f2ce61 100644
--- a/src/starboard/shared/alsa/alsa_audio_sink_type.cc
+++ b/src/starboard/shared/alsa/alsa_audio_sink_type.cc
@@ -14,10 +14,13 @@
#include "starboard/shared/alsa/alsa_audio_sink_type.h"
+#include <alsa/asoundlib.h>
+
#include <algorithm>
#include <vector>
#include "starboard/condition_variable.h"
+#include "starboard/memory.h"
#include "starboard/mutex.h"
#include "starboard/shared/alsa/alsa_util.h"
#include "starboard/thread.h"
@@ -49,6 +52,23 @@
// that is too large can waste some memory as the extra buffer is never used.
const int kALSABufferSizeInFrames = 8192;
+// Helper function to compute the size of the two valid starboard audio sample
+// types.
+size_t GetSampleSize(SbMediaAudioSampleType sample_type) {
+ switch (sample_type) {
+ case kSbMediaAudioSampleTypeFloat32:
+ return sizeof(float);
+ case kSbMediaAudioSampleTypeInt16:
+ return sizeof(int16_t);
+ }
+ SB_NOTREACHED();
+ return 0u;
+}
+
+void* IncrementPointerByBytes(void* pointer, size_t offset) {
+ return static_cast<void*>(static_cast<uint8_t*>(pointer) + offset);
+}
+
// This class is an ALSA based audio sink with the following features:
// 1. It doesn't cache any data internally and maintains minimum data inside
// the ALSA buffer. It relies on pulling data from its source in high
@@ -61,6 +81,7 @@
AlsaAudioSink(Type* type,
int channels,
int sampling_frequency_hz,
+ SbMediaAudioSampleType sample_type,
SbAudioSinkFrameBuffers frame_buffers,
int frames_per_channel,
SbAudioSinkUpdateSourceStatusFunc update_source_status_func,
@@ -95,6 +116,7 @@
int channels_;
int sampling_frequency_hz_;
+ SbMediaAudioSampleType sample_type_;
SbThread audio_out_thread_;
starboard::Mutex mutex_;
@@ -104,9 +126,9 @@
bool destroying_;
- float* frame_buffer_;
+ void* frame_buffer_;
int frames_per_channel_;
- std::vector<float> silence_frames_;
+ void* silence_frames_;
void* playback_handle_;
};
@@ -115,6 +137,7 @@
Type* type,
int channels,
int sampling_frequency_hz,
+ SbMediaAudioSampleType sample_type,
SbAudioSinkFrameBuffers frame_buffers,
int frames_per_channel,
SbAudioSinkUpdateSourceStatusFunc update_source_status_func,
@@ -123,6 +146,7 @@
: type_(type),
channels_(channels),
sampling_frequency_hz_(sampling_frequency_hz),
+ sample_type_(sample_type),
update_source_status_func_(update_source_status_func),
consume_frame_func_(consume_frame_func),
context_(context),
@@ -131,19 +155,23 @@
time_to_wait_(kFramesPerRequest * kSbTimeSecond / sampling_frequency_hz /
2),
destroying_(false),
- frame_buffer_(reinterpret_cast<float*>(frame_buffers[0])),
+ frame_buffer_(frame_buffers[0]),
frames_per_channel_(frames_per_channel),
- silence_frames_(channels * kFramesPerRequest),
+ silence_frames_(new uint8_t[channels * kFramesPerRequest *
+ GetSampleSize(sample_type)]),
playback_handle_(NULL) {
SB_DCHECK(update_source_status_func_);
SB_DCHECK(consume_frame_func_);
SB_DCHECK(frame_buffer_);
+ SB_DCHECK(SbAudioSinkIsAudioSampleTypeSupported(sample_type_));
ScopedLock lock(mutex_);
audio_out_thread_ =
SbThreadCreate(0, kSbThreadPriorityRealTime, kSbThreadNoAffinity, true,
"alsa_audio_out", &AlsaAudioSink::ThreadEntryPoint, this);
SB_DCHECK(SbThreadIsValid(audio_out_thread_));
+ SbMemorySet(silence_frames_, 0,
+ channels * kFramesPerRequest * GetSampleSize(sample_type));
creation_signal_.Wait();
}
@@ -153,6 +181,8 @@
destroying_ = true;
}
SbThreadJoin(audio_out_thread_, NULL);
+
+ delete[] static_cast<uint8_t*>(silence_frames_);
}
// static
@@ -165,9 +195,13 @@
}
void AlsaAudioSink::AudioThreadFunc() {
+ snd_pcm_format_t alsa_sample_type =
+ sample_type_ == kSbMediaAudioSampleTypeFloat32 ? SND_PCM_FORMAT_FLOAT_LE
+ : SND_PCM_FORMAT_S16;
+
playback_handle_ = starboard::shared::alsa::AlsaOpenPlaybackDevice(
channels_, sampling_frequency_hz_, kFramesPerRequest,
- kALSABufferSizeInFrames);
+ kALSABufferSizeInFrames, alsa_sample_type);
creation_signal_.Signal();
if (!playback_handle_) {
return;
@@ -206,7 +240,7 @@
}
int delayed_frame = AlsaGetBufferedFrames(playback_handle_);
if (delayed_frame < kMinimumFramesInALSA) {
- AlsaWriteFrames(playback_handle_, &silence_frames_[0], kFramesPerRequest);
+ AlsaWriteFrames(playback_handle_, silence_frames_, kFramesPerRequest);
} else {
SbThreadSleep(time_to_wait_);
}
@@ -255,9 +289,11 @@
int frames_to_buffer_end = frames_per_channel_ - offset_in_frames;
if (frames_to_write > frames_to_buffer_end) {
- int consumed = AlsaWriteFrames(playback_handle_,
- frame_buffer_ + offset_in_frames * channels_,
- frames_to_buffer_end);
+ int consumed = AlsaWriteFrames(
+ playback_handle_,
+ IncrementPointerByBytes(frame_buffer_, offset_in_frames * channels_ *
+ GetSampleSize(sample_type_)),
+ frames_to_buffer_end);
consume_frame_func_(consumed, context_);
if (consumed != frames_to_buffer_end) {
return;
@@ -267,9 +303,11 @@
offset_in_frames = 0;
}
- int consumed = AlsaWriteFrames(playback_handle_,
- frame_buffer_ + offset_in_frames * channels_,
- frames_to_write);
+ int consumed = AlsaWriteFrames(
+ playback_handle_,
+ IncrementPointerByBytes(frame_buffer_, offset_in_frames * channels_ *
+ GetSampleSize(sample_type_)),
+ frames_to_write);
consume_frame_func_(consumed, context_);
}
@@ -286,8 +324,9 @@
SbAudioSinkConsumeFramesFunc consume_frames_func,
void* context) {
AlsaAudioSink* audio_sink = new AlsaAudioSink(
- this, channels, sampling_frequency_hz, frame_buffers, frames_per_channel,
- update_source_status_func, consume_frames_func, context);
+ this, channels, sampling_frequency_hz, audio_sample_type, frame_buffers,
+ frames_per_channel, update_source_status_func, consume_frames_func,
+ context);
if (!audio_sink->is_valid()) {
delete audio_sink;
return kSbAudioSinkInvalid;
diff --git a/src/starboard/shared/alsa/alsa_util.cc b/src/starboard/shared/alsa/alsa_util.cc
index 6638e81..c713015 100644
--- a/src/starboard/shared/alsa/alsa_util.cc
+++ b/src/starboard/shared/alsa/alsa_util.cc
@@ -92,7 +92,11 @@
void* AlsaOpenPlaybackDevice(int channel,
int sample_rate,
int frames_per_request,
- int buffer_size_in_frames) {
+ int buffer_size_in_frames,
+ snd_pcm_format_t sample_type) {
+ SB_DCHECK(sample_type == SND_PCM_FORMAT_FLOAT_LE ||
+ sample_type == SND_PCM_FORMAT_S16);
+
PcmHandle playback_handle;
int error =
snd_pcm_open(&playback_handle, "default", SND_PCM_STREAM_PLAYBACK, 0);
@@ -111,8 +115,7 @@
SND_PCM_ACCESS_RW_INTERLEAVED);
ALSA_CHECK(error, snd_pcm_hw_params_set_access, NULL);
- error = snd_pcm_hw_params_set_format(playback_handle, hw_params,
- SND_PCM_FORMAT_FLOAT_LE);
+ error = snd_pcm_hw_params_set_format(playback_handle, hw_params, sample_type);
ALSA_CHECK(error, snd_pcm_hw_params_set_format, NULL);
error =
@@ -159,7 +162,7 @@
}
int AlsaWriteFrames(void* playback_handle,
- const float* buffer,
+ const void* buffer,
int frames_to_write) {
if (frames_to_write == 0) {
return 0;
diff --git a/src/starboard/shared/alsa/alsa_util.h b/src/starboard/shared/alsa/alsa_util.h
index 9cfe472..bbbe04f 100644
--- a/src/starboard/shared/alsa/alsa_util.h
+++ b/src/starboard/shared/alsa/alsa_util.h
@@ -15,6 +15,8 @@
#ifndef STARBOARD_SHARED_ALSA_ALSA_UTIL_H_
#define STARBOARD_SHARED_ALSA_ALSA_UTIL_H_
+#include <alsa/asoundlib.h>
+
#include "starboard/shared/internal_only.h"
namespace starboard {
@@ -26,10 +28,11 @@
void* AlsaOpenPlaybackDevice(int channel,
int sample_rate,
int frames_per_request,
- int buffer_size_in_frames);
+ int buffer_size_in_frames,
+ snd_pcm_format_t sample_type);
bool AlsaStartPlay(void* playback_handle);
int AlsaWriteFrames(void* playback_handle,
- const float* buffer,
+ const void* buffer,
int frames_to_write);
int AlsaGetBufferedFrames(void* playback_handle);
void AlsaCloseDevice(void* playback_handle);
diff --git a/src/starboard/shared/linux/page_internal.cc b/src/starboard/shared/linux/page_internal.cc
index 5aec2ed..8b84135 100644
--- a/src/starboard/shared/linux/page_internal.cc
+++ b/src/starboard/shared/linux/page_internal.cc
@@ -44,10 +44,12 @@
mmap_protect |= PROT_WRITE;
flag_set = true;
}
+#if SB_CAN(MAP_EXECUTABLE_MEMORY)
if (sb_flags & kSbMemoryMapProtectExec) {
mmap_protect |= PROT_EXEC;
flag_set = true;
}
+#endif
if (!flag_set) {
mmap_protect = PROT_NONE;
}
diff --git a/src/starboard/shared/pthread/thread_create.cc b/src/starboard/shared/pthread/thread_create.cc
index 813d3ac..70a1fdb 100644
--- a/src/starboard/shared/pthread/thread_create.cc
+++ b/src/starboard/shared/pthread/thread_create.cc
@@ -63,6 +63,14 @@
return kSbThreadInvalid;
}
+#if defined(ADDRESS_SANITIZER)
+ // Set a big thread stack size when in ADDRESS_SANITIZER mode.
+ // This eliminates buffer overflows for deeply nested callstacks.
+ if (stack_size == 0) {
+ stack_size = 4096 * 1024; // 4MB
+ }
+#endif
+
pthread_attr_t attributes;
int result = pthread_attr_init(&attributes);
if (!IsSuccess(result)) {
diff --git a/src/starboard/shared/signal/crash_signals.cc b/src/starboard/shared/signal/crash_signals.cc
index 2ea26a7..5c20870 100644
--- a/src/starboard/shared/signal/crash_signals.cc
+++ b/src/starboard/shared/signal/crash_signals.cc
@@ -61,13 +61,13 @@
void InstallCrashSignalHandlers() {
for (int i = 0; i < SB_ARRAY_SIZE_INT(kSignalsToTrap); ++i) {
- ::signal(i, &DumpStackSignalSafe);
+ ::signal(kSignalsToTrap[i], &DumpStackSignalSafe);
}
}
void UninstallCrashSignalHandlers() {
for (int i = 0; i < SB_ARRAY_SIZE_INT(kSignalsToTrap); ++i) {
- ::signal(i, SIG_DFL);
+ ::signal(kSignalsToTrap[i], SIG_DFL);
}
}
diff --git a/src/starboard/shared/stub/user_start_sign_in.cc b/src/starboard/shared/stub/system_hide_splash_screen.cc
similarity index 90%
rename from src/starboard/shared/stub/user_start_sign_in.cc
rename to src/starboard/shared/stub/system_hide_splash_screen.cc
index 9a99a99..cccc8d5 100644
--- a/src/starboard/shared/stub/user_start_sign_in.cc
+++ b/src/starboard/shared/stub/system_hide_splash_screen.cc
@@ -12,7 +12,6 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#include "starboard/user.h"
+#include "starboard/system.h"
-void SbUserStartSignIn() {
-}
+void SbSystemHideSplashScreen() {}
diff --git a/src/starboard/shared/stub/user_is_age_restricted.cc b/src/starboard/shared/stub/user_is_age_restricted.cc
deleted file mode 100644
index a875b2a..0000000
--- a/src/starboard/shared/stub/user_is_age_restricted.cc
+++ /dev/null
@@ -1,19 +0,0 @@
-// Copyright 2016 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 "starboard/user.h"
-
-bool SbUserIsAgeRestricted(SbUser /*user*/) {
- return false;
-}
diff --git a/src/starboard/stub/configuration_public.h b/src/starboard/stub/configuration_public.h
index 744c7d5..af9c671 100644
--- a/src/starboard/stub/configuration_public.h
+++ b/src/starboard/stub/configuration_public.h
@@ -73,6 +73,9 @@
// wildly varying number of cores.
#define SB_HAS_MANY_CORES 1
+// Whether the current platform is expected to have exactly 1 core.
+#define SB_HAS_1_CORE 0
+
// Whether the current platform is expected to have exactly 2 cores.
#define SB_HAS_2_CORES 0
@@ -299,18 +302,12 @@
// --- Media Configuration ---------------------------------------------------
-// Specifies whether this platform has support for direct access to a decoder
-// for at least H.264/AAC. The decoder is likely to be faster-than-realtime, and
-// it is up to the client to retain decoded frames and display them synchronized
-// with the audio. The decoder must be wired up to the DRM system such that it
-// accepts encrypted samples.
-#define SB_HAS_DECODER 0
-
-// Specifies whether this platform has support for a decrypting elementary
-// stream player for at least AES128-CTR/H.264/AAC. A player is responsible for
-// ingesting an audio and video elementary stream, optionally-encrypted, and
-// ultimately producing synchronized audio/video. If a player is defined, it
-// must choose one of the supported composition methods below.
+// Specifies whether this platform has support for a possibly-decrypting
+// elementary stream player for at least H.264/AAC (and AES-128-CTR, if
+// decrypting). A player is responsible for ingesting an audio and video
+// elementary stream, optionally-encrypted, and ultimately producing
+// synchronized audio/video. If a player is defined, it must choose one of the
+// supported composition methods below.
#define SB_HAS_PLAYER 1
// Specifies whether this platform's player will produce an OpenGL texture that
diff --git a/src/starboard/stub/starboard_platform.gyp b/src/starboard/stub/starboard_platform.gyp
index 1279317..e871191 100644
--- a/src/starboard/stub/starboard_platform.gyp
+++ b/src/starboard/stub/starboard_platform.gyp
@@ -184,6 +184,7 @@
'<(DEPTH)/starboard/shared/stub/system_get_stack.cc',
'<(DEPTH)/starboard/shared/stub/system_get_total_memory.cc',
'<(DEPTH)/starboard/shared/stub/system_has_capability.cc',
+ '<(DEPTH)/starboard/shared/stub/system_hide_splash_screen.cc',
'<(DEPTH)/starboard/shared/stub/system_is_debugger_attached.cc',
'<(DEPTH)/starboard/shared/stub/system_raise_platform_error.cc',
'<(DEPTH)/starboard/shared/stub/system_request_stop.cc',
@@ -212,8 +213,6 @@
'<(DEPTH)/starboard/shared/stub/user_get_current.cc',
'<(DEPTH)/starboard/shared/stub/user_get_property.cc',
'<(DEPTH)/starboard/shared/stub/user_get_signed_in.cc',
- '<(DEPTH)/starboard/shared/stub/user_is_age_restricted.cc',
- '<(DEPTH)/starboard/shared/stub/user_start_sign_in.cc',
'<(DEPTH)/starboard/shared/stub/window_create.cc',
'<(DEPTH)/starboard/shared/stub/window_destroy.cc',
'<(DEPTH)/starboard/shared/stub/window_get_platform_handle.cc',
diff --git a/src/starboard/system.h b/src/starboard/system.h
index 616d421..5cdad66 100644
--- a/src/starboard/system.h
+++ b/src/starboard/system.h
@@ -365,6 +365,11 @@
size_t element_width,
SbSystemComparator comparator);
+// Hides the system splash screen, on systems that support a splash screen that
+// is displayed while the application is loading. This function may be called
+// from any thread and must be idempotent.
+SB_EXPORT void SbSystemHideSplashScreen();
+
#ifdef __cplusplus
} // extern "C"
#endif
diff --git a/src/starboard/user.h b/src/starboard/user.h
index 9dd1e1a..bf9a5d4 100644
--- a/src/starboard/user.h
+++ b/src/starboard/user.h
@@ -96,10 +96,6 @@
// will persist for the lifetime of the app.
SB_EXPORT SbUser SbUserGetCurrent();
-// Returns whether |user| is age-restricted according to the platform's age
-// policies.
-SB_EXPORT bool SbUserIsAgeRestricted(SbUser user);
-
// Gets the size of the value of |property_id| for |user|, INCLUDING the
// terminating null character. Returns 0 if if |user| is invalid, |property_id|
// isn't recognized, supported, or set for |user|.
@@ -113,10 +109,6 @@
char* out_value,
int value_size);
-// Begins the user sign-in flow for the given platform, which may result in a
-// user changed event being dispatched.
-SB_EXPORT void SbUserStartSignIn();
-
#if SB_HAS(USER_APPLICATION_LINKING_SUPPORT)
// Initiates a process to link |user| with a per-application authentication
// token. On success, |out_token| is populated with the authentication token
diff --git a/src/testing/gmock/codereview.settings b/src/testing/gmock/codereview.settings
deleted file mode 100644
index a4b341a..0000000
--- a/src/testing/gmock/codereview.settings
+++ /dev/null
@@ -1,4 +0,0 @@
-# This file is used by gcl to get repository specific information.
-GERRIT_HOST: lbshell-internal-review.googlesource.com
-GERRIT_AUTODETECT_BRANCH: true
-CODE_REVIEW_SERVER: lbshell-internal-review.googlesource.com
diff --git a/src/testing/gtest-parallel/LICENSE b/src/testing/gtest-parallel/LICENSE
new file mode 100644
index 0000000..d645695
--- /dev/null
+++ b/src/testing/gtest-parallel/LICENSE
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ 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.
diff --git a/src/testing/gtest-parallel/README.cobalt b/src/testing/gtest-parallel/README.cobalt
new file mode 100644
index 0000000..0d388eb
--- /dev/null
+++ b/src/testing/gtest-parallel/README.cobalt
@@ -0,0 +1,59 @@
+Name: gtest-parallel
+URL: https://github.com/google/gtest-parallel
+Version: 0
+License: Apache 2.0
+Security Critical: no
+
+Description
+ This directory contains the source code of a python project that helps run
+ gtest binaries in parallel using multiple processes.
+
+How to use
+ Pre-reqs: Python (2)
+ 1. ./gtest-parallel <name-of-gtest-binary>
+
+ for additional options, see ./gtest-parallel --help
+
+ If all the tests pass, you will be see one line on the screen get updated.
+ If a test fails, it will print out the test result and scroll a little bit.
+
+ Example: $ ./gtest-parallel ~/cobalt/src/out/linux-x64x11_debug/layout_tests
+ [436/436] BidiLayoutTests/LayoutTest.LayoutTest/1 (1285 ms)
+
+Troubleshooting
+ 1. Make sure that the gtest-parallel script is executable:
+ chmod +x ./gtest-parallel
+
+Source
+1. a) The external repo was imported into our git server on lbshell-internal,
+ repo name is gtest-parallel
+ b) A new branch was created with the date of last commit
+ c) Then it was pushed to the COBALT branch
+
+ Steps for step 1.b:
+ $ git clone https://lbshell-internal.googlesource.com/testing/gtest-parallel
+ $ cd gtest-parallel/
+ $ git remote add upstream https://github.com/google/gtest-parallel.git
+ $ git fetch upstream
+ $ git checkout -b 20160803 upstream/master
+ $ git push origin
+
+ You will likely need admin permissions on the repo to execute the git push.
+
+2. A patch was applied since gtest now prints some things to stderr instead of
+ stdout.
+
+ $ patch < patches/stderr_out.patch
+
+FAQ
+1. Do the tests need to be thread safe?
+
+ No, the script first asks the binary for the list of tests, and then splits
+ them across multiple processes.
+
+Patches
+1. patches/stderr_out.patch
+
+ Starboard redirects some output from stdout to stderr.
+ Therefore, we needed to modify the the gtest-parallel script to parse stderr
+ instead of stdout.
diff --git a/src/testing/gtest-parallel/gtest-parallel b/src/testing/gtest-parallel/gtest-parallel
new file mode 100755
index 0000000..a258a87
--- /dev/null
+++ b/src/testing/gtest-parallel/gtest-parallel
@@ -0,0 +1,411 @@
+#!/usr/bin/env python2
+# Copyright 2013 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.
+import cPickle
+import errno
+import gzip
+import multiprocessing
+import optparse
+import os
+import signal
+import subprocess
+import sys
+import tempfile
+import thread
+import threading
+import time
+import zlib
+
+# An object that catches SIGINT sent to the Python process and notices
+# if processes passed to wait() die by SIGINT (we need to look for
+# both of those cases, because pressing Ctrl+C can result in either
+# the main process or one of the subprocesses getting the signal).
+#
+# Before a SIGINT is seen, wait(p) will simply call p.wait() and
+# return the result. Once a SIGINT has been seen (in the main process
+# or a subprocess, including the one the current call is waiting for),
+# wait(p) will call p.terminate() and raise ProcessWasInterrupted.
+class SigintHandler(object):
+ class ProcessWasInterrupted(Exception): pass
+ sigint_returncodes = {-signal.SIGINT, # Unix
+ -1073741510, # Windows
+ }
+ def __init__(self):
+ self.__lock = threading.Lock()
+ self.__processes = set()
+ self.__got_sigint = False
+ signal.signal(signal.SIGINT, self.__sigint_handler)
+ def __on_sigint(self):
+ self.__got_sigint = True
+ while self.__processes:
+ try:
+ self.__processes.pop().terminate()
+ except OSError:
+ pass
+ def __sigint_handler(self, signal_num, frame):
+ with self.__lock:
+ self.__on_sigint()
+ def got_sigint(self):
+ with self.__lock:
+ return self.__got_sigint
+ def wait(self, p):
+ with self.__lock:
+ if self.__got_sigint:
+ p.terminate()
+ self.__processes.add(p)
+ code = p.wait()
+ with self.__lock:
+ self.__processes.discard(p)
+ if code in self.sigint_returncodes:
+ self.__on_sigint()
+ if self.__got_sigint:
+ raise self.ProcessWasInterrupted
+ return code
+sigint_handler = SigintHandler()
+
+# Return the width of the terminal, or None if it couldn't be
+# determined (e.g. because we're not being run interactively).
+def term_width(out):
+ if not out.isatty():
+ return None
+ try:
+ p = subprocess.Popen(["stty", "size"],
+ stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ (out, err) = p.communicate()
+ if p.returncode != 0 or err:
+ return None
+ return int(out.split()[1])
+ except (IndexError, OSError, ValueError):
+ return None
+
+# Output transient and permanent lines of text. If several transient
+# lines are written in sequence, the new will overwrite the old. We
+# use this to ensure that lots of unimportant info (tests passing)
+# won't drown out important info (tests failing).
+class Outputter(object):
+ def __init__(self, out_file):
+ self.__out_file = out_file
+ self.__previous_line_was_transient = False
+ self.__width = term_width(out_file) # Line width, or None if not a tty.
+ def transient_line(self, msg):
+ if self.__width is None:
+ self.__out_file.write(msg + "\n")
+ else:
+ self.__out_file.write("\r" + msg[:self.__width].ljust(self.__width))
+ self.__previous_line_was_transient = True
+ def flush_transient_output(self):
+ if self.__previous_line_was_transient:
+ self.__out_file.write("\n")
+ self.__previous_line_was_transient = False
+ def permanent_line(self, msg):
+ self.flush_transient_output()
+ self.__out_file.write(msg + "\n")
+
+stdout_lock = threading.Lock()
+
+class FilterFormat:
+ if sys.stdout.isatty():
+ # stdout needs to be unbuffered since the output is interactive.
+ sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 0)
+
+ out = Outputter(sys.stdout)
+ total_tests = 0
+ finished_tests = 0
+
+ tests = {}
+ outputs = {}
+ failures = []
+
+ def print_test_status(self, last_finished_test, time_ms):
+ self.out.transient_line("[%d/%d] %s (%d ms)"
+ % (self.finished_tests, self.total_tests,
+ last_finished_test, time_ms))
+
+ def handle_meta(self, job_id, args):
+ (command, arg) = args.split(' ', 1)
+ if command == "TEST":
+ (binary, test) = arg.split(' ', 1)
+ self.tests[job_id] = (binary, test.strip())
+ elif command == "EXIT":
+ (exit_code, time_ms) = [int(x) for x in arg.split(' ', 1)]
+ self.finished_tests += 1
+ (binary, test) = self.tests[job_id]
+ self.print_test_status(test, time_ms)
+ if exit_code != 0:
+ self.failures.append(self.tests[job_id])
+ with open(self.outputs[job_id]) as f:
+ for line in f.readlines():
+ self.out.permanent_line(line.rstrip())
+ self.out.permanent_line(
+ "[%d/%d] %s returned/aborted with exit code %d (%d ms)"
+ % (self.finished_tests, self.total_tests, test, exit_code, time_ms))
+ elif command == "TESTCNT":
+ self.total_tests = int(arg.split(' ', 1)[1])
+ self.out.transient_line("[0/%d] Running tests..." % self.total_tests)
+
+ def logfile(self, job_id, name):
+ self.outputs[job_id] = name
+
+ def log(self, line):
+ stdout_lock.acquire()
+ (prefix, output) = line.split(' ', 1)
+
+ assert prefix[-1] == ':'
+ self.handle_meta(int(prefix[:-1]), output)
+ stdout_lock.release()
+
+ def end(self):
+ if self.failures:
+ self.out.permanent_line("FAILED TESTS (%d/%d):"
+ % (len(self.failures), self.total_tests))
+ for (binary, test) in self.failures:
+ self.out.permanent_line(" " + binary + ": " + test)
+ self.out.flush_transient_output()
+
+class RawFormat:
+ def log(self, line):
+ stdout_lock.acquire()
+ sys.stdout.write(line + "\n")
+ sys.stdout.flush()
+ stdout_lock.release()
+ def logfile(self, job_id, name):
+ with open(name) as f:
+ for line in f.readlines():
+ self.log(str(job_id) + '> ' + line.rstrip())
+ def end(self):
+ pass
+
+# Record of test runtimes. Has built-in locking.
+class TestTimes(object):
+ def __init__(self, save_file):
+ "Create new object seeded with saved test times from the given file."
+ self.__times = {} # (test binary, test name) -> runtime in ms
+
+ # Protects calls to record_test_time(); other calls are not
+ # expected to be made concurrently.
+ self.__lock = threading.Lock()
+
+ try:
+ with gzip.GzipFile(save_file, "rb") as f:
+ times = cPickle.load(f)
+ except (EOFError, IOError, cPickle.UnpicklingError, zlib.error):
+ # File doesn't exist, isn't readable, is malformed---whatever.
+ # Just ignore it.
+ return
+
+ # Discard saved times if the format isn't right.
+ if type(times) is not dict:
+ return
+ for ((test_binary, test_name), runtime) in times.items():
+ if (type(test_binary) is not str or type(test_name) is not str
+ or type(runtime) not in {int, long, type(None)}):
+ return
+
+ self.__times = times
+
+ def get_test_time(self, binary, testname):
+ """Return the last duration for the given test as an integer number of
+ milliseconds, or None if the test failed or if there's no record for it."""
+ return self.__times.get((binary, testname), None)
+
+ def record_test_time(self, binary, testname, runtime_ms):
+ """Record that the given test ran in the specified number of
+ milliseconds. If the test failed, runtime_ms should be None."""
+ with self.__lock:
+ self.__times[(binary, testname)] = runtime_ms
+
+ def write_to_file(self, save_file):
+ "Write all the times to file."
+ try:
+ with open(save_file, "wb") as f:
+ with gzip.GzipFile("", "wb", 9, f) as gzf:
+ cPickle.dump(self.__times, gzf, cPickle.HIGHEST_PROTOCOL)
+ except IOError:
+ pass # ignore errors---saving the times isn't that important
+
+# Remove additional arguments (anything after --).
+additional_args = []
+
+for i in range(len(sys.argv)):
+ if sys.argv[i] == '--':
+ additional_args = sys.argv[i+1:]
+ sys.argv = sys.argv[:i]
+ break
+
+parser = optparse.OptionParser(
+ usage = 'usage: %prog [options] binary [binary ...] -- [additional args]')
+
+parser.add_option('-d', '--output_dir', type='string',
+ default=os.path.join(tempfile.gettempdir(), "gtest-parallel"),
+ help='output directory for test logs')
+parser.add_option('-r', '--repeat', type='int', default=1,
+ help='repeat tests')
+parser.add_option('--failed', action='store_true', default=False,
+ help='run only failed and new tests')
+parser.add_option('-w', '--workers', type='int',
+ default=multiprocessing.cpu_count(),
+ help='number of workers to spawn')
+parser.add_option('--gtest_color', type='string', default='yes',
+ help='color output')
+parser.add_option('--gtest_filter', type='string', default='',
+ help='test filter')
+parser.add_option('--gtest_also_run_disabled_tests', action='store_true',
+ default=False, help='run disabled tests too')
+parser.add_option('--format', type='string', default='filter',
+ help='output format (raw,filter)')
+parser.add_option('--print_test_times', action='store_true', default=False,
+ help='When done, list the run time of each test')
+
+(options, binaries) = parser.parse_args()
+
+if binaries == []:
+ parser.print_usage()
+ sys.exit(1)
+
+logger = RawFormat()
+if options.format == 'raw':
+ pass
+elif options.format == 'filter':
+ logger = FilterFormat()
+else:
+ sys.exit("Unknown output format: " + options.format)
+
+# Find tests.
+save_file = os.path.join(os.path.expanduser("~"), ".gtest-parallel-times")
+times = TestTimes(save_file)
+tests = []
+for test_binary in binaries:
+ command = [test_binary]
+ if options.gtest_also_run_disabled_tests:
+ command += ['--gtest_also_run_disabled_tests']
+
+ list_command = list(command)
+ if options.gtest_filter != '':
+ list_command += ['--gtest_filter=' + options.gtest_filter]
+
+ try:
+ test_list = subprocess.Popen(list_command + ['--gtest_list_tests'],
+ stderr=subprocess.PIPE).communicate()[1]
+ except OSError as e:
+ sys.exit("%s: %s" % (test_binary, str(e)))
+
+ command += additional_args
+
+ test_group = ''
+ for line in test_list.split('\n'):
+ if not line.strip():
+ continue
+ if line[0] != " ":
+ # Remove comments for typed tests and strip whitespace.
+ test_group = line.split('#')[0].strip()
+ continue
+ # Remove comments for parameterized tests and strip whitespace.
+ line = line.split('#')[0].strip()
+ if not line:
+ continue
+
+ test = test_group + line
+ if not options.gtest_also_run_disabled_tests and 'DISABLED_' in test:
+ continue
+ tests.append((times.get_test_time(test_binary, test),
+ test_binary, test, command))
+
+if options.failed:
+ # The first element of each entry is the runtime of the most recent
+ # run if it was successful, or None if the test is new or the most
+ # recent run failed.
+ tests = [x for x in tests if x[0] is None]
+
+# Sort tests by falling runtime (with None, which is what we get for
+# new and failing tests, being considered larger than any real
+# runtime).
+tests.sort(reverse=True, key=lambda x: ((1 if x[0] is None else 0), x))
+
+# Repeat tests (-r flag).
+tests *= options.repeat
+test_lock = threading.Lock()
+job_id = 0
+logger.log(str(-1) + ': TESTCNT ' + ' ' + str(len(tests)))
+
+exit_code = 0
+
+# Create directory for test log output.
+try:
+ os.makedirs(options.output_dir)
+except OSError as e:
+ # Ignore errors if this directory already exists.
+ if e.errno != errno.EEXIST or not os.path.isdir(options.output_dir):
+ raise e
+# Remove files from old test runs.
+for logfile in os.listdir(options.output_dir):
+ os.remove(os.path.join(options.output_dir, logfile))
+
+# Run the specified job. Return the elapsed time in milliseconds if
+# the job succeeds, or None if the job fails. (This ensures that
+# failing tests will run first the next time.)
+def run_job((command, job_id, test)):
+ begin = time.time()
+
+ with tempfile.NamedTemporaryFile(dir=options.output_dir, delete=False) as log:
+ sub = subprocess.Popen(command + ['--gtest_filter=' + test] +
+ ['--gtest_color=' + options.gtest_color],
+ stdout=log.file,
+ stderr=log.file)
+ try:
+ code = sigint_handler.wait(sub)
+ except sigint_handler.ProcessWasInterrupted:
+ thread.exit()
+ runtime_ms = int(1000 * (time.time() - begin))
+ logger.logfile(job_id, log.name)
+
+ logger.log("%s: EXIT %s %d" % (job_id, code, runtime_ms))
+ if code == 0:
+ return runtime_ms
+ global exit_code
+ exit_code = code
+ return None
+
+def worker():
+ global job_id
+ while True:
+ job = None
+ test_lock.acquire()
+ if job_id < len(tests):
+ (_, test_binary, test, command) = tests[job_id]
+ logger.log(str(job_id) + ': TEST ' + test_binary + ' ' + test)
+ job = (command, job_id, test)
+ job_id += 1
+ test_lock.release()
+ if job is None:
+ return
+ times.record_test_time(test_binary, test, run_job(job))
+
+def start_daemon(func):
+ t = threading.Thread(target=func)
+ t.daemon = True
+ t.start()
+ return t
+
+workers = [start_daemon(worker) for i in range(options.workers)]
+
+[t.join() for t in workers]
+logger.end()
+times.write_to_file(save_file)
+if options.print_test_times:
+ ts = sorted((times.get_test_time(test_binary, test), test_binary, test)
+ for (_, test_binary, test, _) in tests
+ if times.get_test_time(test_binary, test) is not None)
+ for (time_ms, test_binary, test) in ts:
+ print "%8s %s" % ("%dms" % time_ms, test)
+sys.exit(-signal.SIGINT if sigint_handler.got_sigint() else exit_code)
diff --git a/src/testing/gtest-parallel/patches/stderr_out.patch b/src/testing/gtest-parallel/patches/stderr_out.patch
new file mode 100644
index 0000000..ddaf9df
--- /dev/null
+++ b/src/testing/gtest-parallel/patches/stderr_out.patch
@@ -0,0 +1,19 @@
+commit 0dec4f46db1b072591cb6703c68a2ebb0279026d
+Author: Navreet Gill <navreetgill@google.com>
+Date: Wed Aug 24 11:32:47 2016 -0700
+
+ test
+
+diff --git a/gtest-parallel b/gtest-parallel
+index 4e80928..a258a87 100755
+--- a/gtest-parallel
++++ b/gtest-parallel
+@@ -296,7 +296,7 @@ for test_binary in binaries:
+
+ try:
+ test_list = subprocess.Popen(list_command + ['--gtest_list_tests'],
+- stdout=subprocess.PIPE).communicate()[0]
++ stderr=subprocess.PIPE).communicate()[1]
+ except OSError as e:
+ sys.exit("%s: %s" % (test_binary, str(e)))
+
diff --git a/src/testing/gtest/codereview.settings b/src/testing/gtest/codereview.settings
deleted file mode 100644
index a4b341a..0000000
--- a/src/testing/gtest/codereview.settings
+++ /dev/null
@@ -1,4 +0,0 @@
-# This file is used by gcl to get repository specific information.
-GERRIT_HOST: lbshell-internal-review.googlesource.com
-GERRIT_AUTODETECT_BRANCH: true
-CODE_REVIEW_SERVER: lbshell-internal-review.googlesource.com
diff --git a/src/third_party/WebKit/codereview.settings b/src/third_party/WebKit/codereview.settings
deleted file mode 100644
index a4b341a..0000000
--- a/src/third_party/WebKit/codereview.settings
+++ /dev/null
@@ -1,4 +0,0 @@
-# This file is used by gcl to get repository specific information.
-GERRIT_HOST: lbshell-internal-review.googlesource.com
-GERRIT_AUTODETECT_BRANCH: true
-CODE_REVIEW_SERVER: lbshell-internal-review.googlesource.com
diff --git a/src/third_party/angle/codereview.settings b/src/third_party/angle/codereview.settings
deleted file mode 100644
index 1295fd9..0000000
--- a/src/third_party/angle/codereview.settings
+++ /dev/null
@@ -1,4 +0,0 @@
-# This file is used by gcl to get repository specific information.
-GERRIT_HOST: lbshell-internal-review.googlesource.com
-GERRIT_AUTODETECT_BRANCH: true
-CODE_REVIEW_SERVER: lbshell-internal-review.googlesource.com
diff --git a/src/third_party/dlmalloc/codereview.settings b/src/third_party/dlmalloc/codereview.settings
deleted file mode 100644
index a4b341a..0000000
--- a/src/third_party/dlmalloc/codereview.settings
+++ /dev/null
@@ -1,4 +0,0 @@
-# This file is used by gcl to get repository specific information.
-GERRIT_HOST: lbshell-internal-review.googlesource.com
-GERRIT_AUTODETECT_BRANCH: true
-CODE_REVIEW_SERVER: lbshell-internal-review.googlesource.com
diff --git a/src/third_party/freetype2/codereview.settings b/src/third_party/freetype2/codereview.settings
deleted file mode 100644
index a4b341a..0000000
--- a/src/third_party/freetype2/codereview.settings
+++ /dev/null
@@ -1,4 +0,0 @@
-# This file is used by gcl to get repository specific information.
-GERRIT_HOST: lbshell-internal-review.googlesource.com
-GERRIT_AUTODETECT_BRANCH: true
-CODE_REVIEW_SERVER: lbshell-internal-review.googlesource.com
diff --git a/src/third_party/icu/codereview.settings b/src/third_party/icu/codereview.settings
deleted file mode 100644
index a4b341a..0000000
--- a/src/third_party/icu/codereview.settings
+++ /dev/null
@@ -1,4 +0,0 @@
-# This file is used by gcl to get repository specific information.
-GERRIT_HOST: lbshell-internal-review.googlesource.com
-GERRIT_AUTODETECT_BRANCH: true
-CODE_REVIEW_SERVER: lbshell-internal-review.googlesource.com
diff --git a/src/third_party/libvpx/codereview.settings b/src/third_party/libvpx/codereview.settings
deleted file mode 100644
index d7c8d39..0000000
--- a/src/third_party/libvpx/codereview.settings
+++ /dev/null
@@ -1,4 +0,0 @@
-# This file is used by gcl to get repository specific information.
-GERRIT_HOST: chromium-review.googlesource.com
-GERRIT_PORT: 29418
-CODE_REVIEW_SERVER: chromium-review.googlesource.com
diff --git a/src/third_party/mozjs/codereview.settings b/src/third_party/mozjs/codereview.settings
deleted file mode 100644
index a4b341a..0000000
--- a/src/third_party/mozjs/codereview.settings
+++ /dev/null
@@ -1,4 +0,0 @@
-# This file is used by gcl to get repository specific information.
-GERRIT_HOST: lbshell-internal-review.googlesource.com
-GERRIT_AUTODETECT_BRANCH: true
-CODE_REVIEW_SERVER: lbshell-internal-review.googlesource.com
diff --git a/src/third_party/mozjs/js/src/assembler/wtf/Platform.h b/src/third_party/mozjs/js/src/assembler/wtf/Platform.h
index 2e440e3..05b1155 100644
--- a/src/third_party/mozjs/js/src/assembler/wtf/Platform.h
+++ b/src/third_party/mozjs/js/src/assembler/wtf/Platform.h
@@ -1033,14 +1033,6 @@
#define ENABLE_REPAINT_THROTTLING 0
#endif
-#if defined(WTF_OS_STARBOARD)
-#if SB_CAN(MAP_EXECUTABLE_MEMORY)
-#define ENABLE_JIT 1
-#else
-#define ENABLE_JIT 0
-#endif
-#endif
-
/* Disable the JIT on versions of GCC prior to 4.1 */
#if !defined(ENABLE_JIT) && WTF_COMPILER_GCC && !GCC_VERSION_AT_LEAST(4, 1, 0)
#define ENABLE_JIT 0
@@ -1050,7 +1042,7 @@
#if !defined(ENABLE_JIT) \
&& (WTF_CPU_X86 || WTF_CPU_X86_64 || WTF_CPU_ARM || WTF_CPU_SPARC32 || WTF_CPU_MIPS) \
&& (WTF_OS_DARWIN || !WTF_COMPILER_GCC || GCC_VERSION_AT_LEAST(4, 1, 0)) \
- && !WTF_OS_WINCE
+ && !WTF_OS_WINCE && !defined(WTF_OS_STARBOARD)
#define ENABLE_JIT 1
#endif
diff --git a/src/third_party/mozjs/js/src/jit/CodeGenerator.cpp b/src/third_party/mozjs/js/src/jit/CodeGenerator.cpp
index 294a955..ab8ea02 100644
--- a/src/third_party/mozjs/js/src/jit/CodeGenerator.cpp
+++ b/src/third_party/mozjs/js/src/jit/CodeGenerator.cpp
@@ -715,6 +715,12 @@
}
bool
+CodeGenerator::visitMop(LMop *lir)
+{
+ return true;
+}
+
+bool
CodeGenerator::visitOsiPoint(LOsiPoint *lir)
{
// Note: markOsiPoint ensures enough space exists between the last
@@ -4254,6 +4260,13 @@
masm.add32(Imm32(min), temp);
if (!bailoutIf(Assembler::Overflow, lir->snapshot()))
return false;
+ }
+
+ masm.cmp32(temp, Imm32(0));
+ if (!bailoutIf(Assembler::LessThan, lir->snapshot()))
+ return false;
+
+ if (min != 0) {
int32_t diff;
if (SafeSub(max, min, &diff))
max = diff;
@@ -4261,9 +4274,6 @@
masm.sub32(Imm32(min), temp);
}
- masm.cmp32(temp, Imm32(0));
- if (!bailoutIf(Assembler::LessThan, lir->snapshot()))
- return false;
}
// Compute the maximum possible index. No overflow check is needed when
diff --git a/src/third_party/mozjs/js/src/jit/CodeGenerator.h b/src/third_party/mozjs/js/src/jit/CodeGenerator.h
index 873d7f2..94854d4 100644
--- a/src/third_party/mozjs/js/src/jit/CodeGenerator.h
+++ b/src/third_party/mozjs/js/src/jit/CodeGenerator.h
@@ -51,6 +51,7 @@
bool visitLabel(LLabel *lir);
bool visitNop(LNop *lir);
+ bool visitMop(LMop *lir);
bool visitOsiPoint(LOsiPoint *lir);
bool visitGoto(LGoto *lir);
bool visitTableSwitch(LTableSwitch *ins);
diff --git a/src/third_party/mozjs/js/src/jit/IonCaches.cpp b/src/third_party/mozjs/js/src/jit/IonCaches.cpp
index 30d3711..f833d0f 100644
--- a/src/third_party/mozjs/js/src/jit/IonCaches.cpp
+++ b/src/third_party/mozjs/js/src/jit/IonCaches.cpp
@@ -2522,6 +2522,9 @@
cache.getScriptedLocation(&script, &pc);
RootedValue lval(cx, ObjectValue(*obj));
+ // Override the return value if the script is invalidated (bug 728188).
+ AutoDetectInvalidation adi(cx, res.address(), ion);
+
if (cache.isDisabled()) {
if (!GetElementOperation(cx, JSOp(*pc), &lval, idval, res))
return false;
@@ -2529,9 +2532,7 @@
return true;
}
- // Override the return value if we are invalidated (bug 728188).
- AutoFlushCache afc ("GetElementCache");
- AutoDetectInvalidation adi(cx, res.address(), ion);
+ AutoFlushCache afc("GetElementCache");
RootedId id(cx);
if (!ValueToId<CanGC>(cx, idval, &id))
diff --git a/src/third_party/mozjs/js/src/jit/LIR-Common.h b/src/third_party/mozjs/js/src/jit/LIR-Common.h
index 5a87e04..fb43cfc 100644
--- a/src/third_party/mozjs/js/src/jit/LIR-Common.h
+++ b/src/third_party/mozjs/js/src/jit/LIR-Common.h
@@ -46,6 +46,12 @@
LIR_HEADER(Nop)
};
+class LMop : public LInstructionHelper<0, 0, 0>
+{
+ public:
+ LIR_HEADER(Mop)
+};
+
// An LOsiPoint captures a snapshot after a call and ensures enough space to
// patch in a call to the invalidation mechanism.
//
diff --git a/src/third_party/mozjs/js/src/jit/LOpcodes.h b/src/third_party/mozjs/js/src/jit/LOpcodes.h
index 1520829..dfbd53a 100644
--- a/src/third_party/mozjs/js/src/jit/LOpcodes.h
+++ b/src/third_party/mozjs/js/src/jit/LOpcodes.h
@@ -10,6 +10,7 @@
#define LIR_COMMON_OPCODE_LIST(_) \
_(Label) \
_(Nop) \
+ _(Mop) \
_(OsiPoint) \
_(MoveGroup) \
_(Integer) \
diff --git a/src/third_party/mozjs/js/src/jit/Lowering.cpp b/src/third_party/mozjs/js/src/jit/Lowering.cpp
index fd1dc57..19e7425 100644
--- a/src/third_party/mozjs/js/src/jit/Lowering.cpp
+++ b/src/third_party/mozjs/js/src/jit/Lowering.cpp
@@ -2836,13 +2836,25 @@
ins->setInWorklistUnchecked();
#endif
+ // If we added a Nop for this instruction, we'll also add a Mop, so that
+ // that live-ranges for fixed register defs, which with LSRA extend through
+ // the Nop so that they can extend through the OsiPoint don't, with their
+ // one-extra extension, extend into a position where they use the input
+ // move group for the following instruction.
+ bool needsMop = !current->instructions().empty() && current->rbegin()->isNop();
+
// If no safepoint was created, there's no need for an OSI point.
if (LOsiPoint *osiPoint = popOsiPoint()) {
if (!add(osiPoint))
return false;
}
- return true;
+ if (needsMop) {
+ if (!add(new LMop()))
+ return false;
+ }
+
+ return true;
}
bool
diff --git a/src/third_party/mozjs/js/src/jit/RangeAnalysis.cpp b/src/third_party/mozjs/js/src/jit/RangeAnalysis.cpp
index fd68f91..c8cbc20 100644
--- a/src/third_party/mozjs/js/src/jit/RangeAnalysis.cpp
+++ b/src/third_party/mozjs/js/src/jit/RangeAnalysis.cpp
@@ -339,7 +339,9 @@
// Instead, we should use it to eliminate the dead block.
// (Bug 765127)
if (r->upper_ < r->lower_) {
- *emptyRange = true;
+ // If both ranges can be NaN, the result can still be NaN.
+ if (!lhs->isInfinite() || !rhs->isInfinite())
+ *emptyRange = true;
r->makeRangeInfinite();
}
diff --git a/src/third_party/mozjs/js/src/jit/arm/MacroAssembler-arm.h b/src/third_party/mozjs/js/src/jit/arm/MacroAssembler-arm.h
index 04d68af..c46883a 100644
--- a/src/third_party/mozjs/js/src/jit/arm/MacroAssembler-arm.h
+++ b/src/third_party/mozjs/js/src/jit/arm/MacroAssembler-arm.h
@@ -763,8 +763,9 @@
if (lhs.getTag() == Operand::OP2) {
branch32(cond, lhs.toReg(), rhs, label);
} else {
- ma_ldr(lhs, ScratchRegister);
- branch32(cond, ScratchRegister, rhs, label);
+ // branch32 will use ScratchRegister.
+ ma_ldr(lhs, secondScratchReg_);
+ branch32(cond, secondScratchReg_, rhs, label);
}
}
void branch32(Condition cond, const Address &lhs, Register rhs, Label *label) {
@@ -772,8 +773,9 @@
branch32(cond, ScratchRegister, rhs, label);
}
void branch32(Condition cond, const Address &lhs, Imm32 rhs, Label *label) {
- load32(lhs, ScratchRegister);
- branch32(cond, ScratchRegister, rhs, label);
+ // branch32 will use ScratchRegister.
+ load32(lhs, secondScratchReg_);
+ branch32(cond, secondScratchReg_, rhs, label);
}
void branchPtr(Condition cond, const Address &lhs, Register rhs, Label *label) {
branch32(cond, lhs, rhs, label);
@@ -856,8 +858,9 @@
ma_b(label, cond);
}
void branchTest32(Condition cond, const Address &address, Imm32 imm, Label *label) {
- ma_ldr(Operand(address.base, address.offset), ScratchRegister);
- branchTest32(cond, ScratchRegister, imm, label);
+ // branchTest32 will use ScratchRegister.
+ load32(address, secondScratchReg_);
+ branchTest32(cond, secondScratchReg_, imm, label);
}
void branchTestPtr(Condition cond, const Register &lhs, const Register &rhs, Label *label) {
branchTest32(cond, lhs, rhs, label);
diff --git a/src/third_party/mozjs/js/src/jit/shared/IonAssemblerBufferWithConstantPools.h b/src/third_party/mozjs/js/src/jit/shared/IonAssemblerBufferWithConstantPools.h
index ec0886c..eed3ffd 100644
--- a/src/third_party/mozjs/js/src/jit/shared/IonAssemblerBufferWithConstantPools.h
+++ b/src/third_party/mozjs/js/src/jit/shared/IonAssemblerBufferWithConstantPools.h
@@ -216,8 +216,6 @@
isBranch[idx >> 3] |= 1 << (idx & 0x7);
}
bool isNextBranch() {
- if (this->nodeSize == InstBaseSize)
- return false;
int idx = this->nodeSize / InstBaseSize;
return (isBranch[idx >> 3] >> (idx & 0x7)) & 1;
}
diff --git a/src/third_party/mozjs/js/src/jsbool.cpp b/src/third_party/mozjs/js/src/jsbool.cpp
index 3b97d25..1df3511 100644
--- a/src/third_party/mozjs/js/src/jsbool.cpp
+++ b/src/third_party/mozjs/js/src/jsbool.cpp
@@ -200,7 +200,8 @@
bool
js::BooleanGetPrimitiveValueSlow(HandleObject wrappedBool, JSContext *cx)
{
- JSObject *obj = GetProxyTargetObject(wrappedBool);
- JS_ASSERT(obj);
+ JSObject *obj = CheckedUnwrap(wrappedBool);
+ if (!obj || !obj->is<BooleanObject>())
+ return false;
return obj->as<BooleanObject>().unbox();
}
diff --git a/src/third_party/mozjs/js/src/jsobj.cpp b/src/third_party/mozjs/js/src/jsobj.cpp
index d922358..c8fc252 100644
--- a/src/third_party/mozjs/js/src/jsobj.cpp
+++ b/src/third_party/mozjs/js/src/jsobj.cpp
@@ -279,11 +279,18 @@
if (pobj->isNative()) {
desc->attrs = GetShapeAttributes(shape);
if (desc->attrs & (JSPROP_GETTER | JSPROP_SETTER)) {
+ MOZ_ASSERT(desc.isShared());
doGet = false;
if (desc->attrs & JSPROP_GETTER)
desc->getter = CastAsPropertyOp(shape->getterObject());
if (desc->attrs & JSPROP_SETTER)
desc->setter = CastAsStrictPropertyOp(shape->setterObject());
+ } else {
+ // This is either a straight-up data property or (rarely) a
+ // property with a JSPropertyOp getter/setter. The latter must be
+ // reported to the caller as a plain data property, so don't
+ // populate desc.getter/setter, and mask away the SHARED bit.
+ desc->attrs &= ~JSPROP_SHARED;
}
} else {
if (!JSObject::getGenericAttributes(cx, pobj, id, &desc->attrs))
@@ -5337,4 +5344,3 @@
#endif
}
}
-
diff --git a/src/third_party/mozjs/js/src/jsproxy.cpp b/src/third_party/mozjs/js/src/jsproxy.cpp
index 2dbad14..eddf34f 100644
--- a/src/third_party/mozjs/js/src/jsproxy.cpp
+++ b/src/third_party/mozjs/js/src/jsproxy.cpp
@@ -2328,7 +2328,9 @@
AutoEnterPolicy policy(cx, handler, proxy, id, BaseProxyHandler::GET, true);
if (!policy.allowed())
return policy.returnValue();
- return handler->getOwnPropertyDescriptor(cx, proxy, id, desc, flags);
+ bool ok = handler->getOwnPropertyDescriptor(cx, proxy, id, desc, flags);
+ MOZ_ASSERT_IF(ok && desc.isShared(), desc.hasGetterOrSetterObject());
+ return ok;
}
bool
diff --git a/src/third_party/mozjs/mozjs.gyp b/src/third_party/mozjs/mozjs.gyp
index c3ed096..c646032 100644
--- a/src/third_party/mozjs/mozjs.gyp
+++ b/src/third_party/mozjs/mozjs.gyp
@@ -17,10 +17,11 @@
],
'variables': {
'common_jit_defines': [
+ 'ENABLE_JIT=1',
+ 'ENABLE_YARR_JIT=1',
'JS_ION=1',
'JS_METHODJIT=1',
'JS_METHODJIT_TYPED_ARRAY=1',
- 'ENABLE_YARR_JIT=1',
],
},
'target_defaults': {
@@ -47,20 +48,22 @@
'defines': [
'JS_CPU_X64=1',
'JS_PUNBOX64=1',
- '<@(common_jit_defines)',
],
}],
[ 'target_arch == "x86"', {
'defines': [
'JS_CPU_X86=1',
'JS_NUNBOX32=1',
- '<@(common_jit_defines)',
],
}],
[ 'target_arch == "arm"', {
'defines': [
'JS_CPU_ARM=1',
'JS_NUNBOX32=1',
+ ],
+ }],
+ [ 'cobalt_enable_jit == 1', {
+ 'defines': [
'<@(common_jit_defines)',
],
}],
@@ -98,7 +101,7 @@
'js-confdefs.h',
],
'conditions': [
- [ 'target_arch == "x64"', {
+ [ 'target_arch == "x64" and cobalt_enable_jit == 1', {
'sources': [
'js/src/assembler/assembler/MacroAssemblerX86Common.cpp',
'js/src/jit/shared/Assembler-x86-shared.cpp',
@@ -119,7 +122,7 @@
'<@(mozjs_jit_sources)',
],
}],
- [ 'target_arch == "x86"', {
+ [ 'target_arch == "x86" and cobalt_enable_jit == 1', {
'sources': [
'js/src/assembler/assembler/MacroAssemblerX86Common.cpp',
'js/src/jit/shared/Assembler-x86-shared.cpp',
@@ -140,7 +143,7 @@
'<@(mozjs_jit_sources)',
],
}],
- [ 'target_arch == "arm"', {
+ [ 'target_arch == "arm" and cobalt_enable_jit == 1', {
'sources': [
'js/src/assembler/assembler/ARMAssembler.cpp',
'js/src/assembler/assembler/MacroAssemblerARM.cpp',
diff --git a/src/third_party/openssl/README.chromium b/src/third_party/openssl/README.chromium
index fbae0aa..6c8889b 100644
--- a/src/third_party/openssl/README.chromium
+++ b/src/third_party/openssl/README.chromium
@@ -1,6 +1,6 @@
Name: openssl
URL: http://openssl.org/source/
-Version: 1.0.1c
+Version: 1.0.1p
License: BSDish
License File: openssl/LICENSE
License Android Compatible: yes
diff --git a/src/third_party/openssl/codereview.settings b/src/third_party/openssl/codereview.settings
deleted file mode 100644
index a4b341a..0000000
--- a/src/third_party/openssl/codereview.settings
+++ /dev/null
@@ -1,4 +0,0 @@
-# This file is used by gcl to get repository specific information.
-GERRIT_HOST: lbshell-internal-review.googlesource.com
-GERRIT_AUTODETECT_BRANCH: true
-CODE_REVIEW_SERVER: lbshell-internal-review.googlesource.com
diff --git a/src/third_party/ots/codereview.settings b/src/third_party/ots/codereview.settings
deleted file mode 100644
index acbc431..0000000
--- a/src/third_party/ots/codereview.settings
+++ /dev/null
@@ -1,4 +0,0 @@
-# This file is used by gcl to get repository specific information.
-GERRIT_HOST: lbshell-internal-review.googlesource.com
-GERRIT_AUTODETECT_BRANCH: true
-CODE_REVIEW_SERVER: lbshell-internal-review.googlesource.com
\ No newline at end of file
diff --git a/src/third_party/ots/include/opentype-sanitiser.h b/src/third_party/ots/include/opentype-sanitiser.h
index fc76b90..1380ac7 100644
--- a/src/third_party/ots/include/opentype-sanitiser.h
+++ b/src/third_party/ots/include/opentype-sanitiser.h
@@ -82,8 +82,10 @@
}
while (length >= 4) {
- chksum_ += ntohl(*reinterpret_cast<const uint32_t*>(
- reinterpret_cast<const uint8_t*>(data) + offset));
+ uint32_t tmp;
+ std::memcpy(&tmp, reinterpret_cast<const uint8_t *>(data) + offset,
+ sizeof(uint32_t));
+ chksum_ += ntohl(tmp);
length -= 4;
offset += 4;
}
diff --git a/src/third_party/skia/codereview.settings b/src/third_party/skia/codereview.settings
deleted file mode 100644
index a4b341a..0000000
--- a/src/third_party/skia/codereview.settings
+++ /dev/null
@@ -1,4 +0,0 @@
-# This file is used by gcl to get repository specific information.
-GERRIT_HOST: lbshell-internal-review.googlesource.com
-GERRIT_AUTODETECT_BRANCH: true
-CODE_REVIEW_SERVER: lbshell-internal-review.googlesource.com
diff --git a/src/tools/gyp/codereview.settings b/src/tools/gyp/codereview.settings
deleted file mode 100644
index a4b341a..0000000
--- a/src/tools/gyp/codereview.settings
+++ /dev/null
@@ -1,4 +0,0 @@
-# This file is used by gcl to get repository specific information.
-GERRIT_HOST: lbshell-internal-review.googlesource.com
-GERRIT_AUTODETECT_BRANCH: true
-CODE_REVIEW_SERVER: lbshell-internal-review.googlesource.com