OLD | NEW |
---|---|
1 /* | 1 /* |
2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org) | 2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org) |
3 * (C) 1999 Antti Koivisto (koivisto@kde.org) | 3 * (C) 1999 Antti Koivisto (koivisto@kde.org) |
4 * Copyright (C) 2003, 2007, 2010 Apple Inc. All rights reserved. | 4 * Copyright (C) 2003, 2007, 2010 Apple Inc. All rights reserved. |
5 * | 5 * |
6 * This library is free software; you can redistribute it and/or | 6 * This library is free software; you can redistribute it and/or |
7 * modify it under the terms of the GNU Library General Public | 7 * modify it under the terms of the GNU Library General Public |
8 * License as published by the Free Software Foundation; either | 8 * License as published by the Free Software Foundation; either |
9 * version 2 of the License, or (at your option) any later version. | 9 * version 2 of the License, or (at your option) any later version. |
10 * | 10 * |
11 * This library is distributed in the hope that it will be useful, | 11 * This library is distributed in the hope that it will be useful, |
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of | 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
14 * Library General Public License for more details. | 14 * Library General Public License for more details. |
15 * | 15 * |
16 * You should have received a copy of the GNU Library General Public License | 16 * You should have received a copy of the GNU Library General Public License |
17 * along with this library; see the file COPYING.LIB. If not, write to | 17 * along with this library; see the file COPYING.LIB. If not, write to |
18 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | 18 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
19 * Boston, MA 02110-1301, USA. | 19 * Boston, MA 02110-1301, USA. |
20 * | 20 * |
21 */ | 21 */ |
22 | 22 |
23 #include "core/html/HTMLMarqueeElement.h" | 23 #include "core/html/HTMLMarqueeElement.h" |
24 | 24 |
25 #include "bindings/core/v8/PrivateScriptRunner.h" | 25 #include "bindings/core/v8/ExceptionStatePlaceholder.h" |
26 #include "bindings/core/v8/V8HTMLMarqueeElement.h" | 26 #include "bindings/core/v8/V8HTMLMarqueeElement.h" |
27 #include "core/CSSPropertyNames.h" | |
27 #include "core/HTMLNames.h" | 28 #include "core/HTMLNames.h" |
29 #include "core/animation/DocumentTimeline.h" | |
30 #include "core/animation/KeyframeEffect.h" | |
31 #include "core/animation/KeyframeEffectModel.h" | |
32 #include "core/animation/KeyframeEffectOptions.h" | |
33 #include "core/animation/StringKeyframe.h" | |
34 #include "core/animation/TimingInput.h" | |
35 #include "core/css/CSSStyleDeclaration.h" | |
28 #include "core/dom/Document.h" | 36 #include "core/dom/Document.h" |
37 #include "core/dom/shadow/ShadowRoot.h" | |
38 #include "core/frame/LocalDOMWindow.h" | |
29 #include "core/frame/UseCounter.h" | 39 #include "core/frame/UseCounter.h" |
30 #include "platform/ScriptForbiddenScope.h" | 40 #include "core/html/HTMLDimension.h" |
41 #include <cstdlib> | |
31 | 42 |
32 namespace blink { | 43 namespace blink { |
33 | 44 |
45 namespace { | |
46 | |
47 String convertHTMLLengthToCSSLength(const String& htmlLength) { | |
48 HTMLDimension dimension; | |
49 parseDimensionValue(htmlLength, dimension); | |
50 if (dimension.isRelative()) | |
51 return String(); | |
52 CSSPrimitiveValue* cssValue = CSSPrimitiveValue::create( | |
53 dimension.value(), dimension.isPercentage() | |
54 ? CSSPrimitiveValue::UnitType::Percentage | |
55 : CSSPrimitiveValue::UnitType::Pixels); | |
56 return cssValue->customCSSText(); | |
57 } | |
58 | |
59 } // namespace | |
60 | |
34 inline HTMLMarqueeElement::HTMLMarqueeElement(Document& document) | 61 inline HTMLMarqueeElement::HTMLMarqueeElement(Document& document) |
35 : HTMLElement(HTMLNames::marqueeTag, document) { | 62 : HTMLElement(HTMLNames::marqueeTag, document) { |
36 if (document.contextDocument()) { | |
37 ScriptForbiddenScope::AllowUserAgentScript script; | |
38 v8::Local<v8::Value> classObject = | |
39 PrivateScriptRunner::installClassIfNeeded(&document, | |
40 "HTMLMarqueeElement"); | |
41 RELEASE_ASSERT(!classObject.IsEmpty()); | |
42 } | |
43 UseCounter::count(document, UseCounter::HTMLMarqueeElement); | 63 UseCounter::count(document, UseCounter::HTMLMarqueeElement); |
64 ShadowRoot* shadow = | |
65 createShadowRootInternal(ShadowRootType::V0, ASSERT_NO_EXCEPTION); | |
jbroman
2016/12/01 22:22:52
Ultimately this should probably be a user agent sh
adithyas
2016/12/02 19:29:49
Yup, I'd prefer to do this is in a follow-up, espe
| |
66 Element* style = document.createElement("style"); | |
67 style->setTextContent( | |
68 ":host { display: inline-block; width: -webkit-fill-available; overflow: " | |
69 "hidden; text-align: initial; white-space: nowrap; }" | |
70 ":host([direction=\"up\"]), :host([direction=\"down\"]) { overflow: " | |
71 "initial; overflow-y: hidden; white-space: initial; }" | |
72 ":host > div { will-change: transform; }"); | |
adithyas
2016/12/01 20:30:48
"will-change: transform" is added in to force an a
jbroman
2016/12/01 22:22:52
To elaborate slightly, this layer gets created any
| |
73 shadow->appendChild(style); | |
74 | |
75 Element* mover = document.createElement("div"); | |
76 shadow->appendChild(mover); | |
77 | |
78 mover->appendChild(document.createElement("content")); | |
79 m_mover = mover; | |
44 } | 80 } |
45 | 81 |
46 HTMLMarqueeElement* HTMLMarqueeElement::create(Document& document) { | 82 HTMLMarqueeElement* HTMLMarqueeElement::create(Document& document) { |
47 HTMLMarqueeElement* marqueeElement = new HTMLMarqueeElement(document); | 83 return new HTMLMarqueeElement(document); |
48 V8HTMLMarqueeElement::PrivateScript::createdCallbackMethod(document.frame(), | |
49 marqueeElement); | |
50 return marqueeElement; | |
51 } | 84 } |
52 | 85 |
53 void HTMLMarqueeElement::attributeChanged(const QualifiedName& name, | 86 void HTMLMarqueeElement::attributeChanged(const QualifiedName& name, |
54 const AtomicString& oldValue, | 87 const AtomicString& oldValue, |
55 const AtomicString& newValue, | 88 const AtomicString& newValue, |
56 AttributeModificationReason reason) { | 89 AttributeModificationReason reason) { |
57 HTMLElement::attributeChanged(name, oldValue, newValue, reason); | 90 HTMLElement::attributeChanged(name, oldValue, newValue, reason); |
58 V8HTMLMarqueeElement::PrivateScript::attributeChangedCallbackMethod( | 91 attributeChangedCallback(name, newValue); |
59 document().frame(), this, name.toString(), oldValue, newValue); | |
60 } | 92 } |
61 | 93 |
62 Node::InsertionNotificationRequest HTMLMarqueeElement::insertedInto( | 94 Node::InsertionNotificationRequest HTMLMarqueeElement::insertedInto( |
63 ContainerNode* insertionPoint) { | 95 ContainerNode* insertionPoint) { |
64 HTMLElement::insertedInto(insertionPoint); | 96 HTMLElement::insertedInto(insertionPoint); |
97 | |
65 if (isConnected()) { | 98 if (isConnected()) { |
66 V8HTMLMarqueeElement::PrivateScript::attachedCallbackMethod( | 99 std::vector<QualifiedName> presentationalAttributes = { |
jbroman
2016/12/01 22:22:52
as a rule we prefer WTF::Vector to std::vector ins
adithyas
2016/12/02 19:29:49
Fixed.
| |
67 document().frame(), this); | 100 HTMLNames::bgcolorAttr, HTMLNames::heightAttr, HTMLNames::hspaceAttr, |
101 HTMLNames::vspaceAttr, HTMLNames::widthAttr}; | |
102 for (auto attr : presentationalAttributes) { | |
103 initializeAttribute(attr); | |
104 } | |
105 | |
106 this->start(); | |
jbroman
2016/12/01 22:22:52
nit: in C++, prefer "start();" to "this->start();"
adithyas
2016/12/02 19:29:49
Fixed, here and everywhere else.
| |
68 } | 107 } |
69 return InsertionDone; | 108 return InsertionDone; |
70 } | 109 } |
71 | 110 |
72 void HTMLMarqueeElement::removedFrom(ContainerNode* insertionPoint) { | 111 void HTMLMarqueeElement::removedFrom(ContainerNode* insertionPoint) { |
73 HTMLElement::removedFrom(insertionPoint); | 112 HTMLElement::removedFrom(insertionPoint); |
74 if (insertionPoint->isConnected()) { | 113 if (insertionPoint->isConnected()) { |
75 V8HTMLMarqueeElement::PrivateScript::detachedCallbackMethod( | 114 this->stop(); |
76 insertionPoint->document().frame(), this); | |
77 } | 115 } |
78 } | 116 } |
79 | 117 |
80 bool HTMLMarqueeElement::isHorizontal() const { | 118 bool HTMLMarqueeElement::isHorizontal() const { |
81 AtomicString direction = getAttribute(HTMLNames::directionAttr); | 119 Direction direction = this->direction(); |
82 return direction != "down" && direction != "up"; | 120 return direction != Up && direction != Down; |
121 } | |
122 | |
123 int HTMLMarqueeElement::scrollAmount() { | |
124 bool ok; | |
125 int scrollAmount = getAttribute(HTMLNames::scrollamountAttr).toInt(&ok); | |
126 if (!ok || scrollAmount < 0) { | |
jbroman
2016/12/01 22:22:52
not-really-a-nit: Here and elsewhere, you're free
adithyas
2016/12/02 19:29:49
Removed the braces everywhere I didn't need them.
| |
127 return kDefaultScrollAmount; | |
128 } | |
129 return scrollAmount; | |
130 } | |
131 | |
132 void HTMLMarqueeElement::setScrollAmount(int value, | |
133 ExceptionState& exceptionState) { | |
134 if (value < 0) { | |
135 exceptionState.throwDOMException( | |
jbroman
2016/12/01 22:22:52
Here and elsewhere: ExceptionState::throwDOMExcept
adithyas
2016/12/02 19:29:49
Forgot about that! Fixed.
| |
136 IndexSizeError, | |
137 "The provided value (" + String::number(value) + ") is negative."); | |
138 } | |
139 setIntegralAttribute(HTMLNames::scrollamountAttr, value); | |
140 } | |
141 | |
142 int HTMLMarqueeElement::scrollDelay() { | |
143 bool ok; | |
144 int scrollDelay = getAttribute(HTMLNames::scrolldelayAttr).toInt(&ok); | |
145 if (!ok || scrollDelay < 0) { | |
146 return kDefaultScrollDelayMS; | |
147 } | |
148 return scrollDelay; | |
149 } | |
150 | |
151 void HTMLMarqueeElement::setScrollDelay(int value, | |
152 ExceptionState& exceptionState) { | |
153 if (value < 0) { | |
154 exceptionState.throwDOMException( | |
155 IndexSizeError, | |
156 "The provided value (" + String::number(value) + ") is negative."); | |
157 } | |
158 setIntegralAttribute(HTMLNames::scrolldelayAttr, value); | |
159 } | |
160 | |
161 int HTMLMarqueeElement::loop() { | |
162 bool ok; | |
163 int loop = getAttribute(HTMLNames::loopAttr).toInt(&ok); | |
164 if (!ok || loop <= 0) { | |
165 return kDefaultLoopLimit; | |
166 } | |
167 return loop; | |
168 } | |
169 | |
170 void HTMLMarqueeElement::setLoop(int value, ExceptionState& exceptionState) { | |
171 if (value <= 0 && value != -1) { | |
172 exceptionState.throwDOMException( | |
173 IndexSizeError, "The provided value (" + String::number(value) + | |
174 ") is neither positive nor -1."); | |
175 } | |
176 setIntegralAttribute(HTMLNames::loopAttr, value); | |
177 } | |
178 | |
179 void HTMLMarqueeElement::start() { | |
180 // User script must not run in a SVGImage, but it's okay to run user | |
181 // agent's script such as <marquee>. However, a function scheduled with | |
182 // requestAnimationFrame is indistinguishable if it's scheduled by user | |
183 // script or user agent's script. Thus we disallow scheduling a task | |
184 // in svg (not limited to SVGImage) entirely. | |
185 if (document().hasSVGRootNode()) | |
jbroman
2016/12/01 22:22:52
I wonder if this still applies. Keeping it for now
adithyas
2016/12/02 19:29:49
Removed it, it's not necessary anymore.
| |
186 return; | |
187 | |
188 if (m_continueCallbackRequestId) { | |
189 return; | |
190 } | |
191 RequestAnimationFrameCallback* callback = | |
192 new RequestAnimationFrameCallback(this); | |
193 m_continueCallbackRequestId = document().requestAnimationFrame(callback); | |
194 } | |
195 | |
196 void HTMLMarqueeElement::stop() { | |
197 if (m_continueCallbackRequestId) { | |
198 document().cancelAnimationFrame(m_continueCallbackRequestId); | |
199 m_continueCallbackRequestId = 0; | |
200 return; | |
201 } | |
202 | |
203 if (m_player) { | |
204 m_player->pause(); | |
205 } | |
206 } | |
207 | |
208 void HTMLMarqueeElement::initializeAttribute(const QualifiedName& attr) { | |
209 const AtomicString& value = getAttribute(attr); | |
210 if (value.isNull()) | |
211 return; | |
212 attributeChangedCallback(attr, value); | |
213 } | |
214 | |
215 void HTMLMarqueeElement::attributeChangedCallback(const QualifiedName& attr, | |
216 const String& newValue) { | |
217 if (attr == HTMLNames::bgcolorAttr) { | |
218 style()->setProperty("bgcolor", newValue, String(), ASSERT_NO_EXCEPTION); | |
jbroman
2016/12/01 22:22:52
The CSS property is background-color, not bgcolor.
adithyas
2016/12/02 19:29:49
You are correct, they do use the hyphenated names,
| |
219 } else if (attr == HTMLNames::heightAttr) { | |
220 style()->setProperty("height", convertHTMLLengthToCSSLength(newValue), | |
221 String(), ASSERT_NO_EXCEPTION); | |
222 } else if (attr == HTMLNames::hspaceAttr) { | |
223 style()->setProperty("marginLeft", convertHTMLLengthToCSSLength(newValue), | |
224 String(), ASSERT_NO_EXCEPTION); | |
225 style()->setProperty("marginRight", convertHTMLLengthToCSSLength(newValue), | |
226 String(), ASSERT_NO_EXCEPTION); | |
227 } else if (attr == HTMLNames::vspaceAttr) { | |
228 style()->setProperty("marginTop", convertHTMLLengthToCSSLength(newValue), | |
229 String(), ASSERT_NO_EXCEPTION); | |
230 style()->setProperty("marginBottom", convertHTMLLengthToCSSLength(newValue), | |
231 String(), ASSERT_NO_EXCEPTION); | |
232 } else if (attr == HTMLNames::widthAttr) { | |
233 style()->setProperty("width", convertHTMLLengthToCSSLength(newValue), | |
234 String(), ASSERT_NO_EXCEPTION); | |
235 } | |
236 } | |
237 | |
238 void HTMLMarqueeElement::RequestAnimationFrameCallback::handleEvent(double) { | |
239 m_marquee->m_continueCallbackRequestId = 0; | |
240 m_marquee->continueAnimation(); | |
241 } | |
242 | |
243 void HTMLMarqueeElement::AnimationFinished::handleEvent( | |
244 ExecutionContext* context, | |
245 Event* event) { | |
246 ++m_marquee->m_loopCount; | |
247 m_marquee->start(); | |
248 } | |
249 | |
250 StringKeyframeEffectModel* HTMLMarqueeElement::createEffectModel( | |
251 AnimationParameters& parameters) { | |
252 StringKeyframeVector keyframes; | |
253 StyleSheetContents* styleSheetContents = | |
254 m_mover->document().elementSheet().contents(); | |
255 | |
256 RefPtr<StringKeyframe> keyframe1 = StringKeyframe::create(); | |
257 keyframe1->setCSSPropertyValue(CSSPropertyTransform, | |
258 parameters.transformBegin, styleSheetContents); | |
259 keyframes.append(keyframe1); | |
jbroman
2016/12/01 22:22:52
nit: when passing ownership of a RefPtr, prefer to
adithyas
2016/12/02 19:29:49
Fixed! I'm going to keep using StringKeyFrame unle
| |
260 | |
261 RefPtr<StringKeyframe> keyframe2 = StringKeyframe::create(); | |
262 keyframe2->setCSSPropertyValue(CSSPropertyTransform, parameters.transformEnd, | |
263 styleSheetContents); | |
264 keyframes.append(keyframe2); | |
265 | |
266 StringKeyframeEffectModel* effectModel = StringKeyframeEffectModel::create( | |
267 keyframes, LinearTimingFunction::shared()); | |
268 return effectModel; | |
jbroman
2016/12/01 22:22:52
super-nit: might as well just
return StringKeyfra
adithyas
2016/12/02 19:29:49
Fixed.
| |
269 } | |
270 | |
271 // static | |
272 void HTMLMarqueeElement::initializeTiming(Timing& timing, double duration) { | |
jbroman
2016/12/01 22:22:51
You can just return Timing from this method. Or be
adithyas
2016/12/02 19:29:49
removed the method
| |
273 TimingInput::setFillMode(timing, "forwards"); | |
jbroman
2016/12/01 22:22:52
I'd just use the enum etc here instead of converti
adithyas
2016/12/02 19:29:49
I've changed it to use the enum directly for fill
jbroman
2016/12/03 23:47:31
Ah, OK.
| |
274 UnrestrictedDoubleOrString iterDuration; | |
275 iterDuration.setUnrestrictedDouble(duration); | |
276 TimingInput::setIterationDuration(timing, iterDuration, ASSERT_NO_EXCEPTION); | |
277 } | |
278 | |
279 void HTMLMarqueeElement::continueAnimation() { | |
280 if (!shouldContinue()) { | |
281 return; | |
282 } | |
283 if (m_player && m_player->playState() == "paused") { | |
284 m_player->play(); | |
285 return; | |
286 } | |
287 | |
288 AnimationParameters parameters = getAnimationParameters(); | |
289 int scrollDelay = this->scrollDelay(); | |
290 int scrollAmount = this->scrollAmount(); | |
291 | |
292 if (scrollDelay < kMinimumScrollDelayMS && !trueSpeed()) | |
293 scrollDelay = kDefaultScrollDelayMS; | |
294 double duration = 0; | |
295 if (scrollAmount) | |
296 duration = parameters.distance * scrollDelay / scrollAmount; | |
297 if (!duration) | |
298 return; | |
299 | |
300 StringKeyframeEffectModel* effectModel = createEffectModel(parameters); | |
301 Timing timing; | |
302 initializeTiming(timing, duration); | |
303 KeyframeEffect* keyframeEffect = | |
304 KeyframeEffect::create(m_mover, effectModel, timing); | |
305 Animation* player = m_mover->document().timeline().play(keyframeEffect); | |
306 player->setId(""); | |
jbroman
2016/12/01 22:22:52
nit: "player->setId(emptyString);" is slightly mor
adithyas
2016/12/02 19:29:49
Fixed (assuming you meant emptyString())
jbroman
2016/12/03 23:47:31
Indeed.
| |
307 player->setOnfinish(new AnimationFinished(this)); | |
308 | |
309 m_player = player; | |
310 } | |
311 | |
312 bool HTMLMarqueeElement::shouldContinue() { | |
313 int lp = loop(); | |
314 | |
315 // By default, slide loops only once. | |
316 if (lp <= 0 && behavior() == Slide) | |
317 lp = 1; | |
318 | |
319 if (lp <= 0) | |
320 return true; | |
321 return m_loopCount < lp; | |
322 } | |
323 | |
324 HTMLMarqueeElement::Behavior HTMLMarqueeElement::behavior() const { | |
325 const AtomicString& bhvr = getAttribute(HTMLNames::behaviorAttr); | |
326 if (bhvr == "alternate") | |
327 return Alternate; | |
328 if (bhvr == "slide") | |
329 return Slide; | |
330 return Scroll; | |
331 } | |
332 | |
333 HTMLMarqueeElement::Direction HTMLMarqueeElement::direction() const { | |
334 const AtomicString& dir = getAttribute(HTMLNames::directionAttr); | |
335 if (dir == "down") | |
336 return Down; | |
337 if (dir == "up") | |
338 return Up; | |
339 if (dir == "right") | |
340 return Right; | |
341 return Left; | |
342 } | |
343 | |
344 bool HTMLMarqueeElement::trueSpeed() const { | |
345 return hasAttribute(HTMLNames::truespeedAttr); | |
346 } | |
347 | |
348 HTMLMarqueeElement::Metrics HTMLMarqueeElement::getMetrics() { | |
349 Metrics metrics; | |
350 CSSStyleDeclaration* marqueeStyle = | |
351 document().domWindow()->getComputedStyle(this, String()); | |
352 | |
353 // For marquees that are declared inline, getComputedStyle returns "auto" for | |
354 // width and height. Setting all the metrics to zero disables animation for | |
355 // inline marquees. | |
356 if (marqueeStyle->getPropertyValue("width") == "auto" && | |
357 marqueeStyle->getPropertyValue("height") == "auto") { | |
358 metrics.contentHeight = 0; | |
359 metrics.contentWidth = 0; | |
360 metrics.marqueeWidth = 0; | |
361 metrics.marqueeHeight = 0; | |
362 return metrics; | |
363 } | |
364 | |
365 if (isHorizontal()) { | |
366 m_mover->style()->setProperty("width", "-webkit-max-content", "important", | |
367 ASSERT_NO_EXCEPTION); | |
368 | |
369 } else { | |
370 m_mover->style()->setProperty("height", "-webkit-max-content", "important", | |
371 ASSERT_NO_EXCEPTION); | |
372 } | |
373 | |
374 CSSStyleDeclaration* moverStyle = | |
375 document().domWindow()->getComputedStyle(m_mover, String()); | |
376 | |
377 metrics.contentWidth = moverStyle->getPropertyValue("width").toDouble(); | |
378 metrics.contentHeight = moverStyle->getPropertyValue("height").toDouble(); | |
379 metrics.marqueeWidth = marqueeStyle->getPropertyValue("width").toDouble(); | |
380 metrics.marqueeHeight = marqueeStyle->getPropertyValue("height").toDouble(); | |
381 | |
382 if (isHorizontal()) { | |
383 m_mover->style()->setProperty("width", "", "important", | |
384 ASSERT_NO_EXCEPTION); | |
385 } else { | |
386 m_mover->style()->setProperty("height", "", "important", | |
387 ASSERT_NO_EXCEPTION); | |
388 } | |
389 | |
390 return metrics; | |
391 } | |
392 | |
393 HTMLMarqueeElement::AnimationParameters | |
394 HTMLMarqueeElement::getAnimationParameters() { | |
395 AnimationParameters parameters; | |
396 Metrics metrics = getMetrics(); | |
397 | |
398 double totalWidth = metrics.marqueeWidth + metrics.contentWidth; | |
399 double totalHeight = metrics.marqueeHeight + metrics.contentHeight; | |
400 | |
401 double innerWidth = metrics.marqueeWidth - metrics.contentWidth; | |
402 double innerHeight = metrics.marqueeHeight - metrics.contentHeight; | |
403 | |
404 switch (behavior()) { | |
405 case Alternate: | |
406 switch (direction()) { | |
407 case Right: | |
408 parameters.transformBegin = | |
409 createTransform(false, innerWidth >= 0 ? 0 : innerWidth); | |
410 parameters.transformEnd = | |
411 createTransform(false, innerWidth >= 0 ? innerWidth : 0); | |
412 parameters.distance = std::abs(innerWidth); | |
413 break; | |
414 case Up: | |
415 parameters.transformBegin = | |
416 createTransform(false, innerHeight >= 0 ? innerHeight : 0); | |
417 parameters.transformEnd = | |
418 createTransform(false, innerHeight >= 0 ? 0 : innerHeight); | |
419 parameters.distance = std::abs(innerHeight); | |
420 break; | |
421 case Down: | |
422 parameters.transformBegin = | |
423 createTransform(false, innerHeight >= 0 ? 0 : innerHeight); | |
424 parameters.transformEnd = | |
425 createTransform(false, innerHeight >= 0 ? innerHeight : 0); | |
426 parameters.distance = std::abs(innerHeight); | |
427 break; | |
428 case Left: | |
429 default: | |
430 parameters.transformBegin = | |
431 createTransform(false, innerWidth >= 0 ? innerWidth : 0); | |
432 parameters.transformEnd = | |
433 createTransform(false, innerWidth >= 0 ? 0 : innerWidth); | |
434 parameters.distance = std::abs(innerWidth); | |
435 } | |
436 | |
437 if (m_loopCount % 2) { | |
438 AtomicString transform = parameters.transformBegin; | |
439 parameters.transformBegin = parameters.transformEnd; | |
440 parameters.transformEnd = transform; | |
441 } | |
442 | |
443 break; | |
444 case Slide: | |
445 switch (direction()) { | |
446 case Right: | |
447 parameters.transformBegin = | |
448 createTransform(true, metrics.contentWidth); | |
449 parameters.transformEnd = createTransform(false, innerWidth); | |
450 parameters.distance = metrics.marqueeWidth; | |
451 break; | |
452 case Up: | |
453 parameters.transformBegin = | |
454 createTransform(false, metrics.marqueeHeight); | |
455 parameters.transformEnd = "translateY(0)"; | |
456 parameters.distance = metrics.marqueeHeight; | |
457 break; | |
458 case Down: | |
459 parameters.transformBegin = | |
460 createTransform(true, metrics.contentHeight); | |
461 parameters.transformEnd = createTransform(false, innerHeight); | |
462 parameters.distance = metrics.marqueeHeight; | |
463 break; | |
464 case Left: | |
465 default: | |
466 parameters.transformBegin = | |
467 createTransform(false, metrics.marqueeWidth); | |
468 parameters.transformEnd = "translateX(0)"; | |
469 parameters.distance = metrics.marqueeWidth; | |
470 } | |
471 break; | |
472 case Scroll: | |
473 default: | |
474 switch (direction()) { | |
475 case Right: | |
476 parameters.transformBegin = | |
477 createTransform(true, metrics.contentWidth); | |
478 parameters.transformEnd = | |
479 createTransform(false, metrics.marqueeWidth); | |
480 parameters.distance = totalWidth; | |
481 break; | |
482 case Up: | |
483 parameters.transformBegin = | |
484 createTransform(false, metrics.marqueeHeight); | |
485 parameters.transformEnd = | |
486 createTransform(true, metrics.contentHeight); | |
487 parameters.distance = totalHeight; | |
488 break; | |
489 case Down: | |
490 parameters.transformBegin = | |
491 createTransform(true, metrics.contentHeight); | |
492 parameters.transformEnd = | |
493 createTransform(false, metrics.marqueeHeight); | |
494 parameters.distance = totalHeight; | |
495 break; | |
496 case Left: | |
497 default: | |
498 parameters.transformBegin = | |
499 createTransform(false, metrics.marqueeWidth); | |
500 parameters.transformEnd = createTransform(true, metrics.contentWidth); | |
501 parameters.distance = totalWidth; | |
502 } | |
503 break; | |
504 } | |
505 | |
506 return parameters; | |
507 } | |
508 | |
509 AtomicString HTMLMarqueeElement::createTransform(bool isNegative, | |
510 double value) const { | |
511 char axis = isHorizontal() ? 'X' : 'Y'; | |
512 if (isNegative) | |
513 return AtomicString(String::format("translate%c(-%fpx)", axis, value)); | |
514 return AtomicString(String::format("translate%c(%fpx)", axis, value)); | |
515 } | |
516 | |
517 DEFINE_TRACE(HTMLMarqueeElement) { | |
518 visitor->trace(m_mover); | |
519 visitor->trace(m_player); | |
520 HTMLElement::trace(visitor); | |
83 } | 521 } |
84 | 522 |
85 } // namespace blink | 523 } // namespace blink |
OLD | NEW |