Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "config.h" | 5 #include "config.h" |
| 6 #include "core/dom/CompositorProxy.h" | 6 #include "core/dom/CompositorProxy.h" |
| 7 | 7 |
| 8 #include "bindings/core/v8/ExceptionMessages.h" | 8 #include "bindings/core/v8/ExceptionMessages.h" |
| 9 #include "bindings/core/v8/ExceptionState.h" | 9 #include "bindings/core/v8/ExceptionState.h" |
| 10 #include "core/dom/DOMNodeIds.h" | 10 #include "core/dom/DOMNodeIds.h" |
| 11 #include "core/dom/ExceptionCode.h" | 11 #include "core/dom/ExceptionCode.h" |
| 12 #include "core/dom/ExecutionContext.h" | 12 #include "core/dom/ExecutionContext.h" |
| 13 #include "platform/ThreadSafeFunctional.h" | 13 #include "platform/ThreadSafeFunctional.h" |
| 14 #include "public/platform/Platform.h" | 14 #include "public/platform/Platform.h" |
| 15 #include "public/platform/WebCompositorMutableProperties.h" | |
| 15 #include "public/platform/WebTraceLocation.h" | 16 #include "public/platform/WebTraceLocation.h" |
| 16 | 17 |
| 17 namespace blink { | 18 namespace blink { |
| 18 | 19 |
| 19 struct AttributeFlagMapping { | 20 struct MutablePropertyMapping { |
| 20 const char* name; | 21 const char* name; |
| 21 unsigned length; | 22 unsigned length; |
| 22 CompositorProxy::Attributes attribute; | 23 WebCompositorMutableProperty property; |
| 23 }; | 24 }; |
| 24 | 25 |
| 25 static AttributeFlagMapping allowedAttributes[] = { | 26 // Warning: In order for std::lower_bound to work, the following must be in |
| 26 { "opacity", 7, CompositorProxy::Attributes::OPACITY }, | 27 // alphabetical order. |
| 27 { "scrollleft", 10, CompositorProxy::Attributes::SCROLL_LEFT }, | 28 static MutablePropertyMapping allowedProperties[] = { |
| 28 { "scrolltop", 9, CompositorProxy::Attributes::SCROLL_TOP }, | 29 { "opacity", 7, WebCompositorMutablePropertyOpacity }, |
| 29 { "touch", 5, CompositorProxy::Attributes::TOUCH }, | 30 { "scrollleft", 10, WebCompositorMutablePropertyScrollLeft }, |
| 30 { "transform", 8, CompositorProxy::Attributes::TRANSFORM }, | 31 { "scrolltop", 9, WebCompositorMutablePropertyScrollTop }, |
| 32 { "transform", 9, WebCompositorMutablePropertyTransform }, | |
| 31 }; | 33 }; |
| 32 | 34 |
| 33 static bool CompareAttributeName(const AttributeFlagMapping& attribute, StringIm pl* attributeLower) | 35 static bool ComparePropertyName(const MutablePropertyMapping& mapping, StringImp l* propertyLower) |
|
esprehn
2015/12/07 20:54:24
comparePropertyName
Ian Vollick
2015/12/08 00:16:44
Done.
| |
| 34 { | 36 { |
| 35 ASSERT(attributeLower->is8Bit()); | 37 ASSERT(propertyLower->is8Bit()); |
| 36 return memcmp(attribute.name, attributeLower->characters8(), std::min(attrib ute.length, attributeLower->length())) < 0; | 38 return memcmp(mapping.name, propertyLower->characters8(), std::min(mapping.l ength, propertyLower->length())) < 0; |
| 37 } | 39 } |
| 38 | 40 |
| 39 static CompositorProxy::Attributes attributeFlagForName(const String& attributeN ame) | 41 static WebCompositorMutableProperty compositorMutablePropertyForName(const Strin g& attributeName) |
| 40 { | 42 { |
| 41 CompositorProxy::Attributes attributeFlag = CompositorProxy::Attributes::NON E; | 43 WebCompositorMutableProperty property = WebCompositorMutablePropertyNone; |
| 42 const String attributeLower = attributeName.lower(); | 44 const String attributeLower = attributeName.lower(); |
| 43 const AttributeFlagMapping* start = allowedAttributes; | 45 const MutablePropertyMapping* start = allowedProperties; |
| 44 const AttributeFlagMapping* end = allowedAttributes + WTF_ARRAY_LENGTH(allow edAttributes); | 46 const MutablePropertyMapping* end = allowedProperties + WTF_ARRAY_LENGTH(all owedProperties); |
| 45 if (attributeLower.impl()->is8Bit()) { | 47 if (attributeLower.impl()->is8Bit()) { |
| 46 const AttributeFlagMapping* match = std::lower_bound(start, end, attribu teLower.impl(), CompareAttributeName); | 48 const MutablePropertyMapping* match = std::lower_bound(start, end, attri buteLower.impl(), ComparePropertyName); |
| 47 if (match != end) | 49 if (match != end && equal(match->name, attributeLower.impl())) |
| 48 attributeFlag = match->attribute; | 50 property = match->property; |
| 49 } | 51 } |
| 50 return attributeFlag; | 52 return property; |
| 51 } | 53 } |
| 52 | 54 |
| 53 static bool isControlThread() | 55 static bool isControlThread() |
| 54 { | 56 { |
| 55 return !isMainThread(); | 57 return !isMainThread(); |
| 56 } | 58 } |
| 57 | 59 |
| 58 static bool isCallingCompositorFrameCallback() | 60 static bool isCallingCompositorFrameCallback() |
| 59 { | 61 { |
| 60 // TODO(sad): Check that the requestCompositorFrame callbacks are currently being called. | 62 // TODO(sad): Check that the requestCompositorFrame callbacks are currently being called. |
| 61 return true; | 63 return true; |
| 62 } | 64 } |
| 63 | 65 |
| 64 static void decrementCountForElement(uint64_t elementId) | 66 static void decrementCompositorProxiedPropertiesForElement(uint64_t elementId, u int32_t compositorMutableProperties) |
| 65 { | 67 { |
| 66 ASSERT(isMainThread()); | 68 ASSERT(isMainThread()); |
| 67 Node* node = DOMNodeIds::nodeForId(elementId); | 69 Node* node = DOMNodeIds::nodeForId(elementId); |
| 68 if (!node) | 70 if (!node) |
| 69 return; | 71 return; |
| 70 Element* element = toElement(node); | 72 Element* element = toElement(node); |
| 71 element->decrementProxyCount(); | 73 element->decrementCompositorProxiedProperties(compositorMutableProperties); |
| 72 } | 74 } |
| 73 | 75 |
| 74 static void incrementProxyCountForElement(uint64_t elementId) | 76 static void incrementCompositorProxiedPropertiesForElement(uint64_t elementId, u int32_t compositorMutableProperties) |
| 75 { | 77 { |
| 76 ASSERT(isMainThread()); | 78 ASSERT(isMainThread()); |
| 77 Node* node = DOMNodeIds::nodeForId(elementId); | 79 Node* node = DOMNodeIds::nodeForId(elementId); |
| 78 if (!node) | 80 if (!node) |
| 79 return; | 81 return; |
| 80 Element* element = toElement(node); | 82 Element* element = toElement(node); |
| 81 element->incrementProxyCount(); | 83 element->incrementCompositorProxiedProperties(compositorMutableProperties); |
| 82 } | 84 } |
| 83 | 85 |
| 84 static bool raiseExceptionIfMutationNotAllowed(ExceptionState& exceptionState) | 86 static bool raiseExceptionIfMutationNotAllowed(ExceptionState& exceptionState) |
| 85 { | 87 { |
| 86 if (!isControlThread()) { | 88 if (!isControlThread()) { |
| 87 exceptionState.throwDOMException(NoModificationAllowedError, "Cannot mut ate a proxy attribute from the main page."); | 89 exceptionState.throwDOMException(NoModificationAllowedError, "Cannot mut ate a proxy attribute from the main page."); |
| 88 return true; | 90 return true; |
| 89 } | 91 } |
| 90 if (!isCallingCompositorFrameCallback()) { | 92 if (!isCallingCompositorFrameCallback()) { |
| 91 exceptionState.throwDOMException(NoModificationAllowedError, "Cannot mut ate a proxy attribute outside of a requestCompositorFrame callback."); | 93 exceptionState.throwDOMException(NoModificationAllowedError, "Cannot mut ate a proxy attribute outside of a requestCompositorFrame callback."); |
| 92 return true; | 94 return true; |
| 93 } | 95 } |
| 94 return false; | 96 return false; |
| 95 } | 97 } |
| 96 | 98 |
| 97 static uint32_t attributesBitfieldFromNames(const Vector<String>& attributeArray ) | 99 static uint32_t compositorMutablePropertiesFromNames(const Vector<String>& attri buteArray) |
| 98 { | 100 { |
| 99 uint32_t attributesBitfield = 0; | 101 uint32_t properties = 0; |
| 100 for (const auto& attribute : attributeArray) { | 102 for (const auto& attribute : attributeArray) { |
| 101 attributesBitfield |= static_cast<uint32_t>(attributeFlagForName(attribu te)); | 103 properties |= static_cast<uint32_t>(compositorMutablePropertyForName(att ribute)); |
| 102 } | 104 } |
| 103 return attributesBitfield; | 105 return properties; |
| 104 } | 106 } |
| 105 | 107 |
| 106 #if ENABLE(ASSERT) | 108 #if ENABLE(ASSERT) |
| 107 static bool sanityCheckAttributeFlags(uint32_t attributeFlags) | 109 static bool sanityCheckMutableProperties(uint32_t properties) |
| 108 { | 110 { |
| 109 uint32_t sanityCheckAttributes = attributeFlags; | 111 // Ensures that we only have bits set for valid mutable properties. |
| 110 for (unsigned i = 0; i < arraysize(allowedAttributes); ++i) { | 112 uint32_t sanityCheckProperties = properties; |
| 111 sanityCheckAttributes &= ~static_cast<uint32_t>(allowedAttributes[i].att ribute); | 113 for (unsigned i = 0; i < arraysize(allowedProperties); ++i) { |
| 114 sanityCheckProperties &= ~static_cast<uint32_t>(allowedProperties[i].pro perty); | |
| 112 } | 115 } |
| 113 return !sanityCheckAttributes; | 116 return !sanityCheckProperties; |
| 114 } | 117 } |
| 115 #endif | 118 #endif |
| 116 | 119 |
| 117 CompositorProxy* CompositorProxy::create(ExecutionContext* context, Element* ele ment, const Vector<String>& attributeArray, ExceptionState& exceptionState) | 120 CompositorProxy* CompositorProxy::create(ExecutionContext* context, Element* ele ment, const Vector<String>& attributeArray, ExceptionState& exceptionState) |
| 118 { | 121 { |
| 119 if (!context->isDocument()) { | 122 if (!context->isDocument()) { |
| 120 exceptionState.throwTypeError(ExceptionMessages::failedToConstruct("Comp ositorProxy", "Can only be created from the main context.")); | 123 exceptionState.throwTypeError(ExceptionMessages::failedToConstruct("Comp ositorProxy", "Can only be created from the main context.")); |
| 121 exceptionState.throwIfNeeded(); | 124 exceptionState.throwIfNeeded(); |
| 122 return nullptr; | 125 return nullptr; |
| 123 } | 126 } |
| 124 | 127 |
| 125 return new CompositorProxy(*element, attributeArray); | 128 return new CompositorProxy(*element, attributeArray); |
| 126 } | 129 } |
| 127 | 130 |
| 128 CompositorProxy* CompositorProxy::create(uint64_t elementId, uint32_t attributeF lags) | 131 CompositorProxy* CompositorProxy::create(uint64_t elementId, uint32_t compositor MutableProperties) |
| 129 { | 132 { |
| 130 return new CompositorProxy(elementId, attributeFlags); | 133 return new CompositorProxy(elementId, compositorMutableProperties); |
| 131 } | 134 } |
| 132 | 135 |
| 133 CompositorProxy::CompositorProxy(Element& element, const Vector<String>& attribu teArray) | 136 CompositorProxy::CompositorProxy(Element& element, const Vector<String>& attribu teArray) |
| 134 : m_elementId(DOMNodeIds::idForNode(&element)) | 137 : m_elementId(DOMNodeIds::idForNode(&element)) |
| 135 , m_bitfieldsSupported(attributesBitfieldFromNames(attributeArray)) | 138 , m_compositorMutableProperties(compositorMutablePropertiesFromNames(attribu teArray)) |
| 136 { | 139 { |
| 137 ASSERT(isMainThread()); | 140 ASSERT(isMainThread()); |
| 138 ASSERT(m_bitfieldsSupported); | 141 ASSERT(m_compositorMutableProperties); |
| 139 ASSERT(sanityCheckAttributeFlags(m_bitfieldsSupported)); | 142 ASSERT(sanityCheckMutableProperties(m_compositorMutableProperties)); |
| 140 | 143 |
| 141 incrementProxyCountForElement(m_elementId); | 144 incrementCompositorProxiedPropertiesForElement(m_elementId, m_compositorMuta bleProperties); |
| 142 } | 145 } |
| 143 | 146 |
| 144 CompositorProxy::CompositorProxy(uint64_t elementId, uint32_t attributeFlags) | 147 CompositorProxy::CompositorProxy(uint64_t elementId, uint32_t compositorMutableP roperties) |
| 145 : m_elementId(elementId) | 148 : m_elementId(elementId) |
| 146 , m_bitfieldsSupported(attributeFlags) | 149 , m_compositorMutableProperties(compositorMutableProperties) |
| 147 { | 150 { |
| 148 ASSERT(isControlThread()); | 151 ASSERT(isControlThread()); |
| 149 ASSERT(sanityCheckAttributeFlags(m_bitfieldsSupported)); | 152 ASSERT(sanityCheckMutableProperties(m_compositorMutableProperties)); |
| 150 Platform::current()->mainThread()->taskRunner()->postTask(BLINK_FROM_HERE, t hreadSafeBind(&incrementProxyCountForElement, m_elementId)); | 153 Platform::current()->mainThread()->taskRunner()->postTask(BLINK_FROM_HERE, t hreadSafeBind(&incrementCompositorProxiedPropertiesForElement, m_elementId, m_co mpositorMutableProperties)); |
| 151 } | 154 } |
| 152 | 155 |
| 153 CompositorProxy::~CompositorProxy() | 156 CompositorProxy::~CompositorProxy() |
| 154 { | 157 { |
| 155 if (m_connected) | 158 if (m_connected) |
| 156 disconnect(); | 159 disconnect(); |
| 157 } | 160 } |
| 158 | 161 |
| 159 bool CompositorProxy::supports(const String& attributeName) const | 162 bool CompositorProxy::supports(const String& attributeName) const |
| 160 { | 163 { |
| 161 return !!(m_bitfieldsSupported & static_cast<uint32_t>(attributeFlagForName( attributeName))); | 164 return !!(m_compositorMutableProperties & static_cast<uint32_t>(compositorMu tablePropertyForName(attributeName))); |
| 162 } | 165 } |
| 163 | 166 |
| 164 double CompositorProxy::opacity(ExceptionState& exceptionState) const | 167 double CompositorProxy::opacity(ExceptionState& exceptionState) const |
| 165 { | 168 { |
| 166 if (raiseExceptionIfMutationNotAllowed(exceptionState)) | 169 if (raiseExceptionIfMutationNotAllowed(exceptionState)) |
| 167 return 0.0; | 170 return 0.0; |
| 168 if (raiseExceptionIfNotMutable(Attributes::OPACITY, exceptionState)) | 171 if (raiseExceptionIfNotMutable(static_cast<uint32_t>(WebCompositorMutablePro pertyOpacity), exceptionState)) |
| 169 return 0.0; | 172 return 0.0; |
| 170 return m_opacity; | 173 return m_opacity; |
| 171 } | 174 } |
| 172 | 175 |
| 173 double CompositorProxy::scrollLeft(ExceptionState& exceptionState) const | 176 double CompositorProxy::scrollLeft(ExceptionState& exceptionState) const |
| 174 { | 177 { |
| 175 if (raiseExceptionIfMutationNotAllowed(exceptionState)) | 178 if (raiseExceptionIfMutationNotAllowed(exceptionState)) |
| 176 return 0.0; | 179 return 0.0; |
| 177 if (raiseExceptionIfNotMutable(Attributes::SCROLL_LEFT, exceptionState)) | 180 if (raiseExceptionIfNotMutable(static_cast<uint32_t>(WebCompositorMutablePro pertyScrollLeft), exceptionState)) |
| 178 return 0.0; | 181 return 0.0; |
| 179 return m_scrollLeft; | 182 return m_scrollLeft; |
| 180 } | 183 } |
| 181 | 184 |
| 182 double CompositorProxy::scrollTop(ExceptionState& exceptionState) const | 185 double CompositorProxy::scrollTop(ExceptionState& exceptionState) const |
| 183 { | 186 { |
| 184 if (raiseExceptionIfMutationNotAllowed(exceptionState)) | 187 if (raiseExceptionIfMutationNotAllowed(exceptionState)) |
| 185 return 0.0; | 188 return 0.0; |
| 186 if (raiseExceptionIfNotMutable(Attributes::SCROLL_TOP, exceptionState)) | 189 if (raiseExceptionIfNotMutable(static_cast<uint32_t>(WebCompositorMutablePro pertyScrollTop), exceptionState)) |
| 187 return 0.0; | 190 return 0.0; |
| 188 return m_scrollTop; | 191 return m_scrollTop; |
| 189 } | 192 } |
| 190 | 193 |
| 191 DOMMatrix* CompositorProxy::transform(ExceptionState& exceptionState) const | 194 DOMMatrix* CompositorProxy::transform(ExceptionState& exceptionState) const |
| 192 { | 195 { |
| 193 if (raiseExceptionIfMutationNotAllowed(exceptionState)) | 196 if (raiseExceptionIfMutationNotAllowed(exceptionState)) |
| 194 return nullptr; | 197 return nullptr; |
| 195 if (raiseExceptionIfNotMutable(Attributes::TRANSFORM, exceptionState)) | 198 if (raiseExceptionIfNotMutable(static_cast<uint32_t>(WebCompositorMutablePro pertyTransform), exceptionState)) |
| 196 return nullptr; | 199 return nullptr; |
| 197 return m_transform; | 200 return m_transform; |
| 198 } | 201 } |
| 199 | 202 |
| 200 void CompositorProxy::setOpacity(double opacity, ExceptionState& exceptionState) | 203 void CompositorProxy::setOpacity(double opacity, ExceptionState& exceptionState) |
| 201 { | 204 { |
| 202 if (raiseExceptionIfMutationNotAllowed(exceptionState)) | 205 if (raiseExceptionIfMutationNotAllowed(exceptionState)) |
| 203 return; | 206 return; |
| 204 if (raiseExceptionIfNotMutable(Attributes::OPACITY, exceptionState)) | 207 if (raiseExceptionIfNotMutable(static_cast<uint32_t>(WebCompositorMutablePro pertyOpacity), exceptionState)) |
| 205 return; | 208 return; |
| 206 m_opacity = std::min(1., std::max(0., opacity)); | 209 m_opacity = std::min(1., std::max(0., opacity)); |
| 207 m_mutatedAttributes |= static_cast<uint32_t>(Attributes::OPACITY); | 210 m_mutatedProperties |= static_cast<uint32_t>(WebCompositorMutablePropertyTra nsform); |
| 208 } | 211 } |
| 209 | 212 |
| 210 void CompositorProxy::setScrollLeft(double scrollLeft, ExceptionState& exception State) | 213 void CompositorProxy::setScrollLeft(double scrollLeft, ExceptionState& exception State) |
| 211 { | 214 { |
| 212 if (raiseExceptionIfMutationNotAllowed(exceptionState)) | 215 if (raiseExceptionIfMutationNotAllowed(exceptionState)) |
| 213 return; | 216 return; |
| 214 if (raiseExceptionIfNotMutable(Attributes::SCROLL_LEFT, exceptionState)) | 217 if (raiseExceptionIfNotMutable(static_cast<uint32_t>(WebCompositorMutablePro pertyScrollLeft), exceptionState)) |
| 215 return; | 218 return; |
| 216 m_scrollLeft = scrollLeft; | 219 m_scrollLeft = scrollLeft; |
| 217 m_mutatedAttributes |= static_cast<uint32_t>(Attributes::SCROLL_LEFT); | 220 m_mutatedProperties |= static_cast<uint32_t>(WebCompositorMutablePropertyScr ollLeft); |
| 218 } | 221 } |
| 219 | 222 |
| 220 void CompositorProxy::setScrollTop(double scrollTop, ExceptionState& exceptionSt ate) | 223 void CompositorProxy::setScrollTop(double scrollTop, ExceptionState& exceptionSt ate) |
| 221 { | 224 { |
| 222 if (raiseExceptionIfMutationNotAllowed(exceptionState)) | 225 if (raiseExceptionIfMutationNotAllowed(exceptionState)) |
| 223 return; | 226 return; |
| 224 if (raiseExceptionIfNotMutable(Attributes::SCROLL_TOP, exceptionState)) | 227 if (raiseExceptionIfNotMutable(static_cast<uint32_t>(WebCompositorMutablePro pertyScrollTop), exceptionState)) |
| 225 return; | 228 return; |
| 226 m_scrollTop = scrollTop; | 229 m_scrollTop = scrollTop; |
| 227 m_mutatedAttributes |= static_cast<uint32_t>(Attributes::SCROLL_TOP); | 230 m_mutatedProperties |= static_cast<uint32_t>(WebCompositorMutablePropertyScr ollTop); |
| 228 } | 231 } |
| 229 | 232 |
| 230 void CompositorProxy::setTransform(DOMMatrix* transform, ExceptionState& excepti onState) | 233 void CompositorProxy::setTransform(DOMMatrix* transform, ExceptionState& excepti onState) |
| 231 { | 234 { |
| 232 if (raiseExceptionIfMutationNotAllowed(exceptionState)) | 235 if (raiseExceptionIfMutationNotAllowed(exceptionState)) |
| 233 return; | 236 return; |
| 234 if (raiseExceptionIfNotMutable(Attributes::TRANSFORM, exceptionState)) | 237 if (raiseExceptionIfNotMutable(static_cast<uint32_t>(WebCompositorMutablePro pertyTransform), exceptionState)) |
| 235 return; | 238 return; |
| 236 m_transform = transform; | 239 m_transform = transform; |
| 237 m_mutatedAttributes |= static_cast<uint32_t>(Attributes::TRANSFORM); | 240 m_mutatedProperties |= static_cast<uint32_t>(WebCompositorMutablePropertyTra nsform); |
| 238 } | 241 } |
| 239 | 242 |
| 240 bool CompositorProxy::raiseExceptionIfNotMutable(Attributes attribute, Exception State& exceptionState) const | 243 bool CompositorProxy::raiseExceptionIfNotMutable(uint32_t property, ExceptionSta te& exceptionState) const |
| 241 { | 244 { |
| 242 if (m_connected && (m_bitfieldsSupported & static_cast<uint32_t>(attribute)) ) | 245 if (m_connected && (m_compositorMutableProperties & property)) |
| 243 return false; | 246 return false; |
| 244 exceptionState.throwDOMException(NoModificationAllowedError, | 247 exceptionState.throwDOMException(NoModificationAllowedError, |
| 245 m_connected ? "Attempted to mutate non-mutable attribute." : "Attempted to mutate attribute on a disconnected proxy."); | 248 m_connected ? "Attempted to mutate non-mutable attribute." : "Attempted to mutate attribute on a disconnected proxy."); |
| 246 return true; | 249 return true; |
| 247 } | 250 } |
| 248 | 251 |
| 249 void CompositorProxy::disconnect() | 252 void CompositorProxy::disconnect() |
| 250 { | 253 { |
| 251 m_connected = false; | 254 m_connected = false; |
| 252 if (isMainThread()) | 255 if (isMainThread()) |
| 253 decrementCountForElement(m_elementId); | 256 decrementCompositorProxiedPropertiesForElement(m_elementId, m_compositor MutableProperties); |
| 254 else | 257 else |
| 255 Platform::current()->mainThread()->taskRunner()->postTask(BLINK_FROM_HER E, threadSafeBind(&decrementCountForElement, m_elementId)); | 258 Platform::current()->mainThread()->taskRunner()->postTask(BLINK_FROM_HER E, threadSafeBind(&decrementCompositorProxiedPropertiesForElement, m_elementId, m_compositorMutableProperties)); |
| 256 } | 259 } |
| 257 | 260 |
| 258 } // namespace blink | 261 } // namespace blink |
| OLD | NEW |