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" | |
36 #include "core/css/StylePropertySet.h" | |
28 #include "core/dom/Document.h" | 37 #include "core/dom/Document.h" |
38 #include "core/dom/shadow/ShadowRoot.h" | |
39 #include "core/frame/LocalDOMWindow.h" | |
29 #include "core/frame/UseCounter.h" | 40 #include "core/frame/UseCounter.h" |
30 #include "platform/ScriptForbiddenScope.h" | 41 #include "core/html/HTMLContentElement.h" |
42 #include "core/html/HTMLDimension.h" | |
43 #include "core/html/HTMLDivElement.h" | |
44 #include "core/html/HTMLStyleElement.h" | |
45 #include <cstdlib> | |
31 | 46 |
32 namespace blink { | 47 namespace blink { |
33 | 48 |
49 namespace { | |
50 | |
51 String convertHTMLLengthToCSSLength(const String& htmlLength) { | |
52 HTMLDimension dimension; | |
53 parseDimensionValue(htmlLength, dimension); | |
54 if (dimension.isRelative()) | |
55 return String(); | |
56 CSSPrimitiveValue* cssValue = CSSPrimitiveValue::create( | |
57 dimension.value(), dimension.isPercentage() | |
58 ? CSSPrimitiveValue::UnitType::Percentage | |
59 : CSSPrimitiveValue::UnitType::Pixels); | |
60 return cssValue->customCSSText(); | |
61 } | |
62 | |
63 } // namespace | |
64 | |
34 inline HTMLMarqueeElement::HTMLMarqueeElement(Document& document) | 65 inline HTMLMarqueeElement::HTMLMarqueeElement(Document& document) |
35 : HTMLElement(HTMLNames::marqueeTag, document) { | 66 : 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); | 67 UseCounter::count(document, UseCounter::HTMLMarqueeElement); |
68 ShadowRoot* shadow = | |
69 createShadowRootInternal(ShadowRootType::V0, ASSERT_NO_EXCEPTION); | |
70 Element* style = HTMLStyleElement::create(document, false); | |
71 style->setTextContent( | |
72 ":host { display: inline-block; width: -webkit-fill-available; overflow: " | |
73 "hidden; text-align: initial; white-space: nowrap; }" | |
74 ":host([direction=\"up\"]), :host([direction=\"down\"]) { overflow: " | |
75 "initial; overflow-y: hidden; white-space: initial; }" | |
76 ":host > div { will-change: transform; }"); | |
77 shadow->appendChild(style); | |
78 | |
79 Element* mover = HTMLDivElement::create(document); | |
80 shadow->appendChild(mover); | |
81 | |
82 mover->appendChild(HTMLContentElement::create(document)); | |
83 m_mover = mover; | |
44 } | 84 } |
45 | 85 |
46 HTMLMarqueeElement* HTMLMarqueeElement::create(Document& document) { | 86 HTMLMarqueeElement* HTMLMarqueeElement::create(Document& document) { |
47 HTMLMarqueeElement* marqueeElement = new HTMLMarqueeElement(document); | 87 return new HTMLMarqueeElement(document); |
48 V8HTMLMarqueeElement::PrivateScript::createdCallbackMethod(document.frame(), | |
49 marqueeElement); | |
50 return marqueeElement; | |
51 } | 88 } |
52 | 89 |
53 void HTMLMarqueeElement::attributeChanged(const QualifiedName& name, | 90 void HTMLMarqueeElement::attributeChanged(const QualifiedName& name, |
tkent
2016/12/06 22:43:11
Overriding attributeChanged looks weird. Doesn't
esprehn
2016/12/07 00:10:00
Yes see the discussion for follow up patches
| |
54 const AtomicString& oldValue, | 91 const AtomicString& oldValue, |
55 const AtomicString& newValue, | 92 const AtomicString& newValue, |
56 AttributeModificationReason reason) { | 93 AttributeModificationReason reason) { |
57 HTMLElement::attributeChanged(name, oldValue, newValue, reason); | 94 HTMLElement::attributeChanged(name, oldValue, newValue, reason); |
58 V8HTMLMarqueeElement::PrivateScript::attributeChangedCallbackMethod( | 95 attributeChangedCallback(name, newValue); |
59 document().frame(), this, name.toString(), oldValue, newValue); | |
60 } | 96 } |
61 | 97 |
62 Node::InsertionNotificationRequest HTMLMarqueeElement::insertedInto( | 98 Node::InsertionNotificationRequest HTMLMarqueeElement::insertedInto( |
63 ContainerNode* insertionPoint) { | 99 ContainerNode* insertionPoint) { |
64 HTMLElement::insertedInto(insertionPoint); | 100 HTMLElement::insertedInto(insertionPoint); |
101 | |
65 if (isConnected()) { | 102 if (isConnected()) { |
66 V8HTMLMarqueeElement::PrivateScript::attachedCallbackMethod( | 103 static const QualifiedName* presentationalAttributes[] = { |
67 document().frame(), this); | 104 &HTMLNames::bgcolorAttr, &HTMLNames::heightAttr, &HTMLNames::hspaceAttr, |
68 } | 105 &HTMLNames::vspaceAttr, &HTMLNames::widthAttr}; |
106 for (const auto* attr : presentationalAttributes) { | |
107 const AtomicString& value = getAttribute(*attr); | |
tkent
2016/12/06 22:43:11
getAttribute -> fastGetAttribute
esprehn
2016/12/07 00:10:00
We were trying to avoid using private hooks that a
| |
108 if (value.isNull()) | |
109 continue; | |
110 attributeChangedCallback(*attr, value); | |
111 } | |
112 | |
113 start(); | |
114 } | |
115 | |
69 return InsertionDone; | 116 return InsertionDone; |
70 } | 117 } |
71 | 118 |
72 void HTMLMarqueeElement::removedFrom(ContainerNode* insertionPoint) { | 119 void HTMLMarqueeElement::removedFrom(ContainerNode* insertionPoint) { |
73 HTMLElement::removedFrom(insertionPoint); | 120 HTMLElement::removedFrom(insertionPoint); |
74 if (insertionPoint->isConnected()) { | 121 if (insertionPoint->isConnected()) { |
75 V8HTMLMarqueeElement::PrivateScript::detachedCallbackMethod( | 122 stop(); |
76 insertionPoint->document().frame(), this); | |
77 } | 123 } |
78 } | 124 } |
79 | 125 |
80 bool HTMLMarqueeElement::isHorizontal() const { | 126 bool HTMLMarqueeElement::isHorizontal() const { |
81 AtomicString direction = getAttribute(HTMLNames::directionAttr); | 127 Direction direction = this->direction(); |
82 return direction != "down" && direction != "up"; | 128 return direction != Up && direction != Down; |
129 } | |
130 | |
131 int HTMLMarqueeElement::scrollAmount() const { | |
132 bool ok; | |
133 int scrollAmount = getAttribute(HTMLNames::scrollamountAttr).toInt(&ok); | |
tkent
2016/12/06 22:43:11
Please do not use AtomicString::toInt(). It isn't
esprehn
2016/12/07 00:10:00
Please fix the toInt() to not have an overflow. :)
adithyas
2016/12/08 15:12:11
I'm not really sure about the overflow bug, I coul
| |
134 if (!ok || scrollAmount < 0) | |
135 return kDefaultScrollAmount; | |
136 return scrollAmount; | |
137 } | |
138 | |
139 void HTMLMarqueeElement::setScrollAmount(int value, | |
140 ExceptionState& exceptionState) { | |
141 if (value < 0) { | |
142 exceptionState.throwDOMException( | |
143 IndexSizeError, | |
144 "The provided value (" + String::number(value) + ") is negative."); | |
145 return; | |
146 } | |
147 setIntegralAttribute(HTMLNames::scrollamountAttr, value); | |
148 } | |
149 | |
150 int HTMLMarqueeElement::scrollDelay() const { | |
151 bool ok; | |
152 int scrollDelay = getAttribute(HTMLNames::scrolldelayAttr).toInt(&ok); | |
153 if (!ok || scrollDelay < 0) | |
154 return kDefaultScrollDelayMS; | |
155 return scrollDelay; | |
156 } | |
157 | |
158 void HTMLMarqueeElement::setScrollDelay(int value, | |
159 ExceptionState& exceptionState) { | |
160 if (value < 0) { | |
161 exceptionState.throwDOMException( | |
162 IndexSizeError, | |
163 "The provided value (" + String::number(value) + ") is negative."); | |
164 return; | |
165 } | |
166 setIntegralAttribute(HTMLNames::scrolldelayAttr, value); | |
167 } | |
168 | |
169 int HTMLMarqueeElement::loop() const { | |
170 bool ok; | |
171 int loop = getAttribute(HTMLNames::loopAttr).toInt(&ok); | |
172 if (!ok || loop <= 0) | |
173 return kDefaultLoopLimit; | |
174 return loop; | |
175 } | |
176 | |
177 void HTMLMarqueeElement::setLoop(int value, ExceptionState& exceptionState) { | |
178 if (value <= 0 && value != -1) { | |
179 exceptionState.throwDOMException( | |
180 IndexSizeError, "The provided value (" + String::number(value) + | |
181 ") is neither positive nor -1."); | |
182 return; | |
183 } | |
184 setIntegralAttribute(HTMLNames::loopAttr, value); | |
185 } | |
186 | |
187 void HTMLMarqueeElement::start() { | |
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 void HTMLMarqueeElement::attributeChangedCallback(const QualifiedName& attr, | |
208 const String& newValue) { | |
209 if (attr == HTMLNames::bgcolorAttr) { | |
210 style()->setProperty("background-color", newValue, String(), | |
211 ASSERT_NO_EXCEPTION); | |
212 } else if (attr == HTMLNames::heightAttr) { | |
213 style()->setProperty("height", convertHTMLLengthToCSSLength(newValue), | |
214 String(), ASSERT_NO_EXCEPTION); | |
215 } else if (attr == HTMLNames::hspaceAttr) { | |
216 style()->setProperty("margin-left", convertHTMLLengthToCSSLength(newValue), | |
217 String(), ASSERT_NO_EXCEPTION); | |
218 style()->setProperty("margin-right", convertHTMLLengthToCSSLength(newValue), | |
219 String(), ASSERT_NO_EXCEPTION); | |
220 } else if (attr == HTMLNames::vspaceAttr) { | |
221 style()->setProperty("margin-top", convertHTMLLengthToCSSLength(newValue), | |
222 String(), ASSERT_NO_EXCEPTION); | |
223 style()->setProperty("margin-bottom", | |
224 convertHTMLLengthToCSSLength(newValue), String(), | |
225 ASSERT_NO_EXCEPTION); | |
226 } else if (attr == HTMLNames::widthAttr) { | |
227 style()->setProperty("width", convertHTMLLengthToCSSLength(newValue), | |
228 String(), ASSERT_NO_EXCEPTION); | |
229 } | |
230 } | |
231 | |
232 void HTMLMarqueeElement::RequestAnimationFrameCallback::handleEvent(double) { | |
233 m_marquee->m_continueCallbackRequestId = 0; | |
234 m_marquee->continueAnimation(); | |
235 } | |
236 | |
237 void HTMLMarqueeElement::AnimationFinished::handleEvent( | |
238 ExecutionContext* context, | |
239 Event* event) { | |
240 ++m_marquee->m_loopCount; | |
241 m_marquee->start(); | |
242 } | |
243 | |
244 StringKeyframeEffectModel* HTMLMarqueeElement::createEffectModel( | |
245 AnimationParameters& parameters) { | |
tkent
2016/12/06 22:43:11
The argument type should be |const AnimationParame
| |
246 StyleSheetContents* styleSheetContents = | |
247 m_mover->document().elementSheet().contents(); | |
248 MutableStylePropertySet::SetResult setResult; | |
249 | |
250 RefPtr<StringKeyframe> keyframe1 = StringKeyframe::create(); | |
251 setResult = keyframe1->setCSSPropertyValue( | |
252 CSSPropertyTransform, parameters.transformBegin, styleSheetContents); | |
253 DCHECK(setResult.didParse); | |
254 | |
255 RefPtr<StringKeyframe> keyframe2 = StringKeyframe::create(); | |
256 setResult = keyframe2->setCSSPropertyValue( | |
257 CSSPropertyTransform, parameters.transformEnd, styleSheetContents); | |
258 DCHECK(setResult.didParse); | |
259 | |
260 return StringKeyframeEffectModel::create( | |
261 {std::move(keyframe1), std::move(keyframe2)}, | |
262 LinearTimingFunction::shared()); | |
263 } | |
264 | |
265 void HTMLMarqueeElement::continueAnimation() { | |
266 if (!shouldContinue()) | |
267 return; | |
268 | |
269 if (m_player && m_player->playState() == "paused") { | |
270 m_player->play(); | |
271 return; | |
272 } | |
273 | |
274 AnimationParameters parameters = getAnimationParameters(); | |
275 int scrollDelay = this->scrollDelay(); | |
276 int scrollAmount = this->scrollAmount(); | |
277 | |
278 if (scrollDelay < kMinimumScrollDelayMS && !trueSpeed()) | |
279 scrollDelay = kDefaultScrollDelayMS; | |
280 double duration = 0; | |
281 if (scrollAmount) | |
282 duration = parameters.distance * scrollDelay / scrollAmount; | |
283 if (!duration) | |
284 return; | |
285 | |
286 StringKeyframeEffectModel* effectModel = createEffectModel(parameters); | |
287 Timing timing; | |
288 timing.fillMode = Timing::FillMode::FORWARDS; | |
289 TimingInput::setIterationDuration( | |
290 timing, UnrestrictedDoubleOrString::fromUnrestrictedDouble(duration), | |
291 ASSERT_NO_EXCEPTION); | |
292 | |
293 KeyframeEffect* keyframeEffect = | |
294 KeyframeEffect::create(m_mover, effectModel, timing); | |
295 Animation* player = m_mover->document().timeline().play(keyframeEffect); | |
296 player->setId(emptyString()); | |
297 player->setOnfinish(new AnimationFinished(this)); | |
298 | |
299 m_player = player; | |
300 } | |
301 | |
302 bool HTMLMarqueeElement::shouldContinue() { | |
303 int loopCount = loop(); | |
304 | |
305 // By default, slide loops only once. | |
306 if (loopCount <= 0 && behavior() == Slide) | |
307 loopCount = 1; | |
308 | |
309 if (loopCount <= 0) | |
310 return true; | |
311 return m_loopCount < loopCount; | |
312 } | |
313 | |
314 HTMLMarqueeElement::Behavior HTMLMarqueeElement::behavior() const { | |
315 const AtomicString& behavior = getAttribute(HTMLNames::behaviorAttr); | |
316 if (behavior == "alternate") | |
tkent
2016/12/06 22:43:11
Should it be case-sensitive match?
adithyas
2016/12/08 15:12:11
Nope, this is a bug, thanks for catching it.
| |
317 return Alternate; | |
318 if (behavior == "slide") | |
319 return Slide; | |
320 return Scroll; | |
321 } | |
322 | |
323 HTMLMarqueeElement::Direction HTMLMarqueeElement::direction() const { | |
324 const AtomicString& direction = getAttribute(HTMLNames::directionAttr); | |
325 if (direction == "down") | |
326 return Down; | |
327 if (direction == "up") | |
328 return Up; | |
329 if (direction == "right") | |
330 return Right; | |
331 return Left; | |
332 } | |
333 | |
334 bool HTMLMarqueeElement::trueSpeed() const { | |
335 return hasAttribute(HTMLNames::truespeedAttr); | |
tkent
2016/12/06 22:43:11
hasAttribute -> fastHasAttribute
| |
336 } | |
337 | |
338 HTMLMarqueeElement::Metrics HTMLMarqueeElement::getMetrics() { | |
339 Metrics metrics; | |
340 CSSStyleDeclaration* marqueeStyle = | |
341 document().domWindow()->getComputedStyle(this, String()); | |
342 // For marquees that are declared inline, getComputedStyle returns "auto" for | |
343 // width and height. Setting all the metrics to zero disables animation for | |
344 // inline marquees. | |
345 if (marqueeStyle->getPropertyValue("width") == "auto" && | |
346 marqueeStyle->getPropertyValue("height") == "auto") { | |
347 metrics.contentHeight = 0; | |
348 metrics.contentWidth = 0; | |
349 metrics.marqueeWidth = 0; | |
350 metrics.marqueeHeight = 0; | |
351 return metrics; | |
352 } | |
353 | |
354 if (isHorizontal()) { | |
355 m_mover->style()->setProperty("width", "-webkit-max-content", "important", | |
356 ASSERT_NO_EXCEPTION); | |
357 } else { | |
358 m_mover->style()->setProperty("height", "-webkit-max-content", "important", | |
359 ASSERT_NO_EXCEPTION); | |
360 } | |
361 CSSStyleDeclaration* moverStyle = | |
362 document().domWindow()->getComputedStyle(m_mover, String()); | |
363 | |
364 metrics.contentWidth = moverStyle->getPropertyValue("width").toDouble(); | |
365 metrics.contentHeight = moverStyle->getPropertyValue("height").toDouble(); | |
366 metrics.marqueeWidth = marqueeStyle->getPropertyValue("width").toDouble(); | |
367 metrics.marqueeHeight = marqueeStyle->getPropertyValue("height").toDouble(); | |
368 | |
369 if (isHorizontal()) { | |
370 m_mover->style()->setProperty("width", "", "important", | |
371 ASSERT_NO_EXCEPTION); | |
372 } else { | |
373 m_mover->style()->setProperty("height", "", "important", | |
374 ASSERT_NO_EXCEPTION); | |
375 } | |
376 | |
377 return metrics; | |
378 } | |
379 | |
380 HTMLMarqueeElement::AnimationParameters | |
381 HTMLMarqueeElement::getAnimationParameters() { | |
382 AnimationParameters parameters; | |
383 Metrics metrics = getMetrics(); | |
384 | |
385 double totalWidth = metrics.marqueeWidth + metrics.contentWidth; | |
386 double totalHeight = metrics.marqueeHeight + metrics.contentHeight; | |
387 | |
388 double innerWidth = metrics.marqueeWidth - metrics.contentWidth; | |
389 double innerHeight = metrics.marqueeHeight - metrics.contentHeight; | |
390 | |
391 switch (behavior()) { | |
392 case Alternate: | |
393 switch (direction()) { | |
394 case Right: | |
395 parameters.transformBegin = | |
396 createTransform(innerWidth >= 0 ? 0 : innerWidth); | |
397 parameters.transformEnd = | |
398 createTransform(innerWidth >= 0 ? innerWidth : 0); | |
399 parameters.distance = std::abs(innerWidth); | |
400 break; | |
401 case Up: | |
402 parameters.transformBegin = | |
403 createTransform(innerHeight >= 0 ? innerHeight : 0); | |
404 parameters.transformEnd = | |
405 createTransform(innerHeight >= 0 ? 0 : innerHeight); | |
406 parameters.distance = std::abs(innerHeight); | |
407 break; | |
408 case Down: | |
409 parameters.transformBegin = | |
410 createTransform(innerHeight >= 0 ? 0 : innerHeight); | |
411 parameters.transformEnd = | |
412 createTransform(innerHeight >= 0 ? innerHeight : 0); | |
413 parameters.distance = std::abs(innerHeight); | |
414 break; | |
415 case Left: | |
416 default: | |
417 parameters.transformBegin = | |
418 createTransform(innerWidth >= 0 ? innerWidth : 0); | |
419 parameters.transformEnd = | |
420 createTransform(innerWidth >= 0 ? 0 : innerWidth); | |
421 parameters.distance = std::abs(innerWidth); | |
422 } | |
423 | |
424 if (m_loopCount % 2) | |
425 std::swap(parameters.transformBegin, parameters.transformEnd); | |
426 break; | |
427 case Slide: | |
428 switch (direction()) { | |
429 case Right: | |
430 parameters.transformBegin = createTransform(-metrics.contentWidth); | |
431 parameters.transformEnd = createTransform(innerWidth); | |
432 parameters.distance = metrics.marqueeWidth; | |
433 break; | |
434 case Up: | |
435 parameters.transformBegin = createTransform(metrics.marqueeHeight); | |
436 parameters.transformEnd = "translateY(0)"; | |
437 parameters.distance = metrics.marqueeHeight; | |
438 break; | |
439 case Down: | |
440 parameters.transformBegin = createTransform(-metrics.contentHeight); | |
441 parameters.transformEnd = createTransform(innerHeight); | |
442 parameters.distance = metrics.marqueeHeight; | |
443 break; | |
444 case Left: | |
445 default: | |
446 parameters.transformBegin = createTransform(metrics.marqueeWidth); | |
447 parameters.transformEnd = "translateX(0)"; | |
448 parameters.distance = metrics.marqueeWidth; | |
449 } | |
450 break; | |
451 case Scroll: | |
452 default: | |
453 switch (direction()) { | |
454 case Right: | |
455 parameters.transformBegin = createTransform(-metrics.contentWidth); | |
456 parameters.transformEnd = createTransform(metrics.marqueeWidth); | |
457 parameters.distance = totalWidth; | |
458 break; | |
459 case Up: | |
460 parameters.transformBegin = createTransform(metrics.marqueeHeight); | |
461 parameters.transformEnd = createTransform(-metrics.contentHeight); | |
462 parameters.distance = totalHeight; | |
463 break; | |
464 case Down: | |
465 parameters.transformBegin = createTransform(-metrics.contentHeight); | |
466 parameters.transformEnd = createTransform(metrics.marqueeHeight); | |
467 parameters.distance = totalHeight; | |
468 break; | |
469 case Left: | |
470 default: | |
471 parameters.transformBegin = createTransform(metrics.marqueeWidth); | |
472 parameters.transformEnd = createTransform(-metrics.contentWidth); | |
473 parameters.distance = totalWidth; | |
474 } | |
475 break; | |
476 } | |
477 | |
478 return parameters; | |
479 } | |
480 | |
481 AtomicString HTMLMarqueeElement::createTransform(double value) const { | |
482 char axis = isHorizontal() ? 'X' : 'Y'; | |
483 return AtomicString(String::format("translate%c(%fpx)", axis, value)); | |
tkent
2016/12/06 22:43:11
Does this work in French locale, which use ',' for
adithyas
2016/12/08 15:12:11
I don't think it does, thanks for pointing this ou
| |
484 } | |
485 | |
486 DEFINE_TRACE(HTMLMarqueeElement) { | |
487 visitor->trace(m_mover); | |
488 visitor->trace(m_player); | |
489 HTMLElement::trace(visitor); | |
83 } | 490 } |
84 | 491 |
85 } // namespace blink | 492 } // namespace blink |
OLD | NEW |