Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(146)

Side by Side Diff: third_party/WebKit/Source/core/html/HTMLMarqueeElement.cpp

Issue 2549443003: Move <marquee> implementation to HTMLMarqueeElement.cpp (Closed)
Patch Set: Move out transform string creation into separate method Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698