15c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)/*
25c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.
35c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * Copyright (C) 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
45c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *
55c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * Portions are Copyright (C) 1998 Netscape Communications Corporation.
65c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *
75c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * Other contributors:
85c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *   Robert O'Callahan <roc+@cs.cmu.edu>
95c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *   David Baron <dbaron@fas.harvard.edu>
105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *   Christian Biesinger <cbiesinger@web.de>
115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *   Randall Jesup <rjesup@wgate.com>
125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *   Roland Mainz <roland.mainz@informatik.med.uni-giessen.de>
135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *   Josh Soref <timeless@mac.com>
145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *   Boris Zbarsky <bzbarsky@mit.edu>
155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *
165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * This library is free software; you can redistribute it and/or
175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * modify it under the terms of the GNU Lesser General Public
185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * License as published by the Free Software Foundation; either
195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * version 2.1 of the License, or (at your option) any later version.
205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *
215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * This library is distributed in the hope that it will be useful,
225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * but WITHOUT ANY WARRANTY; without even the implied warranty of
235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * Lesser General Public License for more details.
255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *
265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * You should have received a copy of the GNU Lesser General Public
275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * License along with this library; if not, write to the Free Software
285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *
305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * Alternatively, the contents of this file may be used under the terms
315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * of either the Mozilla Public License Version 1.1, found at
325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * http://www.mozilla.org/MPL/ (the "MPL") or the GNU General Public
335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * License Version 2.0, found at http://www.fsf.org/copyleft/gpl.html
345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * (the "GPL"), in which case the provisions of the MPL or the GPL are
355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * applicable instead of those above.  If you wish to allow use of your
365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * version of this file only under the terms of one of those two
375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * licenses (the MPL or the GPL) and not to allow others to use your
385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * version of this file under the LGPL, indicate your decision by
395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * deletingthe provisions above and replace them with the notice and
405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * other provisions required by the MPL or the GPL, as the case may be.
415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * If you do not delete the provisions above, a recipient may use your
425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * version of this file under any of the LGPL, the MPL or the GPL.
435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) */
445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "config.h"
465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
4753e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "core/rendering/RenderMarquee.h"
485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
495d92fedcae5e801a8b224de090094f2d9df0b54aTorne (Richard Coles)#include "core/HTMLNames.h"
5053e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "core/html/HTMLMarqueeElement.h"
511e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)#include "core/frame/FrameView.h"
5251b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)#include "core/frame/UseCounter.h"
5353e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "core/rendering/RenderLayer.h"
5453e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "core/rendering/RenderView.h"
5509380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)#include "platform/LengthFunctions.h"
565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
57c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)namespace blink {
585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)using namespace HTMLNames;
605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
6109380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)RenderMarquee::RenderMarquee(HTMLMarqueeElement* element)
628abfc5808a4e34d6e03867af8bc440dee641886fTorne (Richard Coles)    : RenderBlockFlow(element)
63521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)    , m_currentLoop(0)
645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    , m_totalLoops(0)
6509380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    , m_timer(element, &HTMLMarqueeElement::timerFired)
66521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)    , m_start(0)
67521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)    , m_end(0)
68521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)    , m_speed(0)
69521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)    , m_reset(false)
70521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)    , m_suspended(false)
71521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)    , m_stopped(false)
72521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)    , m_direction(MAUTO)
735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
741e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)    UseCounter::count(document(), UseCounter::HTMLMarqueeElement);
755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)RenderMarquee::~RenderMarquee()
785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)int RenderMarquee::marqueeSpeed() const
825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
83521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)    int result = style()->marqueeSpeed();
848abfc5808a4e34d6e03867af8bc440dee641886fTorne (Richard Coles)    if (Node* node = this->node())
858abfc5808a4e34d6e03867af8bc440dee641886fTorne (Richard Coles)        result = std::max(result, toHTMLMarqueeElement(node)->minimumDelay());
865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return result;
875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)EMarqueeDirection RenderMarquee::direction() const
905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // FIXME: Support the CSS3 "auto" value for determining the direction of the marquee.
925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // For now just map MAUTO to MBACKWARD
93521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)    EMarqueeDirection result = style()->marqueeDirection();
94521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)    TextDirection dir = style()->direction();
955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (result == MAUTO)
965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        result = MBACKWARD;
975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (result == MFORWARD)
985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        result = (dir == LTR) ? MRIGHT : MLEFT;
995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (result == MBACKWARD)
1005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        result = (dir == LTR) ? MLEFT : MRIGHT;
10102772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
1025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // Now we have the real direction.  Next we check to see if the increment is negative.
1035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // If so, then we reverse the direction.
104521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)    Length increment = style()->marqueeIncrement();
1055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (increment.isNegative())
1065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        result = static_cast<EMarqueeDirection>(-result);
10702772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
1085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return result;
1095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
1105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)bool RenderMarquee::isHorizontal() const
1125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
1135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return direction() == MLEFT || direction() == MRIGHT;
1145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
1155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)int RenderMarquee::computePosition(EMarqueeDirection dir, bool stopAtContentEdge)
1175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
1185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (isHorizontal()) {
119521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)        bool ltr = style()->isLeftToRightDirection();
120521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)        LayoutUnit clientWidth = this->clientWidth();
121521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)        LayoutUnit contentWidth = ltr ? maxPreferredLogicalWidth() : minPreferredLogicalWidth();
1225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (ltr)
123521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)            contentWidth += (paddingRight() - borderLeft());
1245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        else {
125521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)            contentWidth = width() - contentWidth;
126521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)            contentWidth += (paddingLeft() - borderRight());
1275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
1285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (dir == MRIGHT) {
1295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if (stopAtContentEdge)
130197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch                return std::max<LayoutUnit>(0, ltr ? (contentWidth - clientWidth) : (clientWidth - contentWidth));
1315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            else
1325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                return ltr ? contentWidth : clientWidth;
1335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
1345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        else {
1355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if (stopAtContentEdge)
136197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch                return std::min<LayoutUnit>(0, ltr ? (contentWidth - clientWidth) : (clientWidth - contentWidth));
1375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            else
1385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                return ltr ? -clientWidth : -contentWidth;
1395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
1405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
1415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    else {
142521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)        int contentHeight = layoutOverflowRect().maxY() - borderTop() + paddingBottom();
143521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)        int clientHeight = this->clientHeight();
1445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (dir == MUP) {
1455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if (stopAtContentEdge)
146197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch                return std::min(contentHeight - clientHeight, 0);
1475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            else
1485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                return -clientHeight;
1495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
1505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        else {
1515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if (stopAtContentEdge)
152197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch                return std::max(contentHeight - clientHeight, 0);
15302772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch            else
1545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                return contentHeight;
1555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
15602772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch    }
1575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
1585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)void RenderMarquee::start()
1605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
161521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)    if (m_timer.isActive() || style()->marqueeIncrement().isZero())
1625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return;
1635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (!m_suspended && !m_stopped) {
1655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (isHorizontal())
166bfe3590b1806e3ff18f46ee3af5d4b83078f305aTorne (Richard Coles)            layer()->scrollableArea()->scrollToOffset(IntSize(m_start, 0));
1675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        else
168bfe3590b1806e3ff18f46ee3af5d4b83078f305aTorne (Richard Coles)            layer()->scrollableArea()->scrollToOffset(IntSize(0, m_start));
1691e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)    } else {
1705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        m_suspended = false;
1715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        m_stopped = false;
1725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
1735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
174d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    m_timer.startRepeating(speed() * 0.001, FROM_HERE);
1755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
1765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)void RenderMarquee::suspend()
1785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
1795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    m_timer.stop();
1805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    m_suspended = true;
1815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
1825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)void RenderMarquee::stop()
1845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
1855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    m_timer.stop();
1865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    m_stopped = true;
1875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
1885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)void RenderMarquee::updateMarqueePosition()
1905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
1915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    bool activate = (m_totalLoops <= 0 || m_currentLoop < m_totalLoops);
1925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (activate) {
193521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)        EMarqueeBehavior behavior = style()->marqueeBehavior();
1945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        m_start = computePosition(direction(), behavior == MALTERNATE);
1955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        m_end = computePosition(reverseDirection(), behavior == MALTERNATE || behavior == MSLIDE);
196d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)        if (!m_stopped) {
197d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)            // Hits in compositing/overflow/do-not-repaint-if-scrolling-composited-layers.html during layout.
198d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)            DisableCompositingQueryAsserts disabler;
1995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            start();
200d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)        }
2015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
2025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
2035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
204521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)const char* RenderMarquee::renderName() const
2055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
206521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)    if (isFloating())
207521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)        return "RenderMarquee (floating)";
208521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)    if (isOutOfFlowPositioned())
209521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)        return "RenderMarquee (positioned)";
210521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)    if (isAnonymous())
211521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)        return "RenderMarquee (generated)";
212521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)    if (isRelPositioned())
213521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)        return "RenderMarquee (relative positioned)";
214521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)    return "RenderMarquee";
215521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)
216521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)}
217521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)
218521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)void RenderMarquee::styleDidChange(StyleDifference difference, const RenderStyle* oldStyle)
219521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles){
22009380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    RenderBlockFlow::styleDidChange(difference, oldStyle);
221521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)
222521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)    RenderStyle* s = style();
22302772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
2245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (m_direction != s->marqueeDirection() || (m_totalLoops != s->marqueeLoopCount() && m_currentLoop >= m_totalLoops))
2255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        m_currentLoop = 0; // When direction changes or our loopCount is a smaller number than our current loop, reset our loop.
22602772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
2275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    m_totalLoops = s->marqueeLoopCount();
2285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    m_direction = s->marqueeDirection();
22902772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
230521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)    // Hack for WinIE. In WinIE, a value of 0 or lower for the loop count for SLIDE means to only do
231521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)    // one loop.
232521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)    if (m_totalLoops <= 0 && s->marqueeBehavior() == MSLIDE)
233521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)        m_totalLoops = 1;
234521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)
235521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)    // Hack alert: Set the white-space value to nowrap for horizontal marquees with inline children, thus ensuring
236521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)    // all the text ends up on one line by default. Limit this hack to the <marquee> element to emulate
237521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)    // WinIE's behavior. Someone using CSS3 can use white-space: nowrap on their own to get this effect.
238521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)    // Second hack alert: Set the text-align back to auto. WinIE completely ignores text-align on the
239521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)    // marquee element.
240521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)    // FIXME: Bring these up with the CSS WG.
241521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)    if (isHorizontal() && childrenInline()) {
242521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)        s->setWhiteSpace(NOWRAP);
243521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)        s->setTextAlign(TASTART);
2445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
245521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)
2465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // Legacy hack - multiple browsers default vertical marquees to 200px tall.
2475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (!isHorizontal() && s->height().isAuto())
24802772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch        s->setHeight(Length(200, Fixed));
24902772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
2505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (speed() != marqueeSpeed()) {
2515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        m_speed = marqueeSpeed();
2525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (m_timer.isActive())
253d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)            m_timer.startRepeating(speed() * 0.001, FROM_HERE);
2545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
25502772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
2565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // Check the loop count to see if we should now stop.
2575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    bool activate = (m_totalLoops <= 0 || m_currentLoop < m_totalLoops);
2585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (activate && !m_timer.isActive())
2595d92fedcae5e801a8b224de090094f2d9df0b54aTorne (Richard Coles)        setNeedsLayoutAndFullPaintInvalidation();
2605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    else if (!activate && m_timer.isActive())
2615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        m_timer.stop();
2625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
2635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
26409380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)void RenderMarquee::layoutBlock(bool relayoutChildren)
265591b958dee2cf159d33a0b931e6231072eaf38d5Ben Murdoch{
26609380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    RenderBlockFlow::layoutBlock(relayoutChildren);
267591b958dee2cf159d33a0b931e6231072eaf38d5Ben Murdoch
268591b958dee2cf159d33a0b931e6231072eaf38d5Ben Murdoch    updateMarqueePosition();
269591b958dee2cf159d33a0b931e6231072eaf38d5Ben Murdoch}
270591b958dee2cf159d33a0b931e6231072eaf38d5Ben Murdoch
27109380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)void RenderMarquee::timerFired()
2725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
273521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)    // FIXME: Why do we need to check the view and not just the RenderMarquee itself?
274521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)    if (view()->needsLayout())
2755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return;
27602772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
2775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (m_reset) {
2785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        m_reset = false;
2795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (isHorizontal())
280bfe3590b1806e3ff18f46ee3af5d4b83078f305aTorne (Richard Coles)            layer()->scrollableArea()->scrollToXOffset(m_start);
2815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        else
282bfe3590b1806e3ff18f46ee3af5d4b83078f305aTorne (Richard Coles)            layer()->scrollableArea()->scrollToYOffset(m_start);
2835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return;
2845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
28502772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
286521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)    RenderStyle* s = style();
28702772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
2885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    int endPoint = m_end;
2895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    int range = m_end - m_start;
2905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    int newPos;
2915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (range == 0)
2925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        newPos = m_end;
29302772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch    else {
2945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        bool addIncrement = direction() == MUP || direction() == MLEFT;
2955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        bool isReversed = s->marqueeBehavior() == MALTERNATE && m_currentLoop % 2;
2965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (isReversed) {
2975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            // We're going in the reverse direction.
2985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            endPoint = m_start;
2995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            range = -range;
3005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            addIncrement = !addIncrement;
3015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
3025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        bool positive = range > 0;
303521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)        int clientSize = (isHorizontal() ? clientWidth() : clientHeight());
304521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)        int increment = abs(intValueForLength(style()->marqueeIncrement(), clientSize));
305bfe3590b1806e3ff18f46ee3af5d4b83078f305aTorne (Richard Coles)        int currentPos = (isHorizontal() ? layer()->scrollableArea()->scrollXOffset() : layer()->scrollableArea()->scrollYOffset());
3065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        newPos =  currentPos + (addIncrement ? increment : -increment);
3075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (positive)
308197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch            newPos = std::min(newPos, endPoint);
3095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        else
310197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch            newPos = std::max(newPos, endPoint);
3115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
3125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (newPos == endPoint) {
3145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        m_currentLoop++;
3155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (m_totalLoops > 0 && m_currentLoop >= m_totalLoops)
3165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            m_timer.stop();
3175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        else if (s->marqueeBehavior() != MALTERNATE)
3185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            m_reset = true;
3195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
32002772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
3215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (isHorizontal())
322bfe3590b1806e3ff18f46ee3af5d4b83078f305aTorne (Richard Coles)        layer()->scrollableArea()->scrollToXOffset(newPos);
3235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    else
324bfe3590b1806e3ff18f46ee3af5d4b83078f305aTorne (Richard Coles)        layer()->scrollableArea()->scrollToYOffset(newPos);
3255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
3265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
327c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)} // namespace blink
328