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
3 // found in the LICENSE file.
6 #include "core/dom/CompositorProxy.h"
8 #include "bindings/core/v8/ExceptionMessages.h"
9 #include "bindings/core/v8/ExceptionState.h"
10 #include "core/dom/DOMNodeIds.h"
11 #include "core/dom/ExceptionCode.h"
12 #include "core/dom/ExecutionContext.h"
13 #include "platform/ThreadSafeFunctional.h"
14 #include "public/platform/Platform.h"
15 #include "public/platform/WebTraceLocation.h"
19 struct AttributeFlagMapping
{
22 CompositorProxy::Attributes attribute
;
25 static AttributeFlagMapping allowedAttributes
[] = {
26 { "opacity", 7, CompositorProxy::Attributes::OPACITY
},
27 { "scrollleft", 10, CompositorProxy::Attributes::SCROLL_LEFT
},
28 { "scrolltop", 9, CompositorProxy::Attributes::SCROLL_TOP
},
29 { "touch", 5, CompositorProxy::Attributes::TOUCH
},
30 { "transform", 8, CompositorProxy::Attributes::TRANSFORM
},
33 static bool CompareAttributeName(const AttributeFlagMapping
& attribute
, StringImpl
* attributeLower
)
35 ASSERT(attributeLower
->is8Bit());
36 return memcmp(attribute
.name
, attributeLower
->characters8(), std::min(attribute
.length
, attributeLower
->length())) < 0;
39 static CompositorProxy::Attributes
attributeFlagForName(const String
& attributeName
)
41 CompositorProxy::Attributes attributeFlag
= CompositorProxy::Attributes::NONE
;
42 const String attributeLower
= attributeName
.lower();
43 const AttributeFlagMapping
* start
= allowedAttributes
;
44 const AttributeFlagMapping
* end
= allowedAttributes
+ WTF_ARRAY_LENGTH(allowedAttributes
);
45 if (attributeLower
.impl()->is8Bit()) {
46 const AttributeFlagMapping
* match
= std::lower_bound(start
, end
, attributeLower
.impl(), CompareAttributeName
);
48 attributeFlag
= match
->attribute
;
53 static bool isControlThread()
55 return !isMainThread();
58 static bool isCallingCompositorFrameCallback()
60 // TODO(sad): Check that the requestCompositorFrame callbacks are currently being called.
64 static void decrementCountForElement(uint64_t elementId
)
66 ASSERT(isMainThread());
67 Node
* node
= DOMNodeIds::nodeForId(elementId
);
70 Element
* element
= toElement(node
);
71 element
->decrementProxyCount();
74 static void incrementProxyCountForElement(uint64_t elementId
)
76 ASSERT(isMainThread());
77 Node
* node
= DOMNodeIds::nodeForId(elementId
);
80 Element
* element
= toElement(node
);
81 element
->incrementProxyCount();
84 static bool raiseExceptionIfMutationNotAllowed(ExceptionState
& exceptionState
)
86 if (!isControlThread()) {
87 exceptionState
.throwDOMException(NoModificationAllowedError
, "Cannot mutate a proxy attribute from the main page.");
90 if (!isCallingCompositorFrameCallback()) {
91 exceptionState
.throwDOMException(NoModificationAllowedError
, "Cannot mutate a proxy attribute outside of a requestCompositorFrame callback.");
97 static uint32_t attributesBitfieldFromNames(const Vector
<String
>& attributeArray
)
99 uint32_t attributesBitfield
= 0;
100 for (const auto& attribute
: attributeArray
) {
101 attributesBitfield
|= static_cast<uint32_t>(attributeFlagForName(attribute
));
103 return attributesBitfield
;
107 static bool sanityCheckAttributeFlags(uint32_t attributeFlags
)
109 uint32_t sanityCheckAttributes
= attributeFlags
;
110 for (unsigned i
= 0; i
< arraysize(allowedAttributes
); ++i
) {
111 sanityCheckAttributes
&= ~static_cast<uint32_t>(allowedAttributes
[i
].attribute
);
113 return !sanityCheckAttributes
;
117 CompositorProxy
* CompositorProxy::create(ExecutionContext
* context
, Element
* element
, const Vector
<String
>& attributeArray
, ExceptionState
& exceptionState
)
119 if (!context
->isDocument()) {
120 exceptionState
.throwTypeError(ExceptionMessages::failedToConstruct("CompositorProxy", "Can only be created from the main context."));
121 exceptionState
.throwIfNeeded();
125 return new CompositorProxy(*element
, attributeArray
);
128 CompositorProxy
* CompositorProxy::create(uint64_t elementId
, uint32_t attributeFlags
)
130 return new CompositorProxy(elementId
, attributeFlags
);
133 CompositorProxy::CompositorProxy(Element
& element
, const Vector
<String
>& attributeArray
)
134 : m_elementId(DOMNodeIds::idForNode(&element
))
135 , m_bitfieldsSupported(attributesBitfieldFromNames(attributeArray
))
137 ASSERT(isMainThread());
138 ASSERT(m_bitfieldsSupported
);
139 ASSERT(sanityCheckAttributeFlags(m_bitfieldsSupported
));
141 incrementProxyCountForElement(m_elementId
);
144 CompositorProxy::CompositorProxy(uint64_t elementId
, uint32_t attributeFlags
)
145 : m_elementId(elementId
)
146 , m_bitfieldsSupported(attributeFlags
)
148 ASSERT(isControlThread());
149 ASSERT(sanityCheckAttributeFlags(m_bitfieldsSupported
));
150 Platform::current()->mainThread()->taskRunner()->postTask(FROM_HERE
, threadSafeBind(&incrementProxyCountForElement
, m_elementId
));
153 CompositorProxy::~CompositorProxy()
159 bool CompositorProxy::supports(const String
& attributeName
) const
161 return !!(m_bitfieldsSupported
& static_cast<uint32_t>(attributeFlagForName(attributeName
)));
164 double CompositorProxy::opacity(ExceptionState
& exceptionState
) const
166 if (raiseExceptionIfMutationNotAllowed(exceptionState
))
168 if (raiseExceptionIfNotMutable(Attributes::OPACITY
, exceptionState
))
173 double CompositorProxy::scrollLeft(ExceptionState
& exceptionState
) const
175 if (raiseExceptionIfMutationNotAllowed(exceptionState
))
177 if (raiseExceptionIfNotMutable(Attributes::SCROLL_LEFT
, exceptionState
))
182 double CompositorProxy::scrollTop(ExceptionState
& exceptionState
) const
184 if (raiseExceptionIfMutationNotAllowed(exceptionState
))
186 if (raiseExceptionIfNotMutable(Attributes::SCROLL_TOP
, exceptionState
))
191 DOMMatrix
* CompositorProxy::transform(ExceptionState
& exceptionState
) const
193 if (raiseExceptionIfMutationNotAllowed(exceptionState
))
195 if (raiseExceptionIfNotMutable(Attributes::TRANSFORM
, exceptionState
))
200 void CompositorProxy::setOpacity(double opacity
, ExceptionState
& exceptionState
)
202 if (raiseExceptionIfMutationNotAllowed(exceptionState
))
204 if (raiseExceptionIfNotMutable(Attributes::OPACITY
, exceptionState
))
206 m_opacity
= std::min(1., std::max(0., opacity
));
207 m_mutatedAttributes
|= static_cast<uint32_t>(Attributes::OPACITY
);
210 void CompositorProxy::setScrollLeft(double scrollLeft
, ExceptionState
& exceptionState
)
212 if (raiseExceptionIfMutationNotAllowed(exceptionState
))
214 if (raiseExceptionIfNotMutable(Attributes::SCROLL_LEFT
, exceptionState
))
216 m_scrollLeft
= scrollLeft
;
217 m_mutatedAttributes
|= static_cast<uint32_t>(Attributes::SCROLL_LEFT
);
220 void CompositorProxy::setScrollTop(double scrollTop
, ExceptionState
& exceptionState
)
222 if (raiseExceptionIfMutationNotAllowed(exceptionState
))
224 if (raiseExceptionIfNotMutable(Attributes::SCROLL_TOP
, exceptionState
))
226 m_scrollTop
= scrollTop
;
227 m_mutatedAttributes
|= static_cast<uint32_t>(Attributes::SCROLL_TOP
);
230 void CompositorProxy::setTransform(DOMMatrix
* transform
, ExceptionState
& exceptionState
)
232 if (raiseExceptionIfMutationNotAllowed(exceptionState
))
234 if (raiseExceptionIfNotMutable(Attributes::TRANSFORM
, exceptionState
))
236 m_transform
= transform
;
237 m_mutatedAttributes
|= static_cast<uint32_t>(Attributes::TRANSFORM
);
240 bool CompositorProxy::raiseExceptionIfNotMutable(Attributes attribute
, ExceptionState
& exceptionState
) const
242 if (m_connected
&& (m_bitfieldsSupported
& static_cast<uint32_t>(attribute
)))
244 exceptionState
.throwDOMException(NoModificationAllowedError
,
245 m_connected
? "Attempted to mutate non-mutable attribute." : "Attempted to mutate attribute on a disconnected proxy.");
249 void CompositorProxy::disconnect()
253 decrementCountForElement(m_elementId
);
255 Platform::current()->mainThread()->taskRunner()->postTask(FROM_HERE
, threadSafeBind(&decrementCountForElement
, m_elementId
));