From cad810f21b803229eb11403f9209855525a25d57 Mon Sep 17 00:00:00 2001 From: Steve Block Date: Fri, 6 May 2011 11:45:16 +0100 Subject: Merge WebKit at r75315: Initial merge by git. Change-Id: I570314b346ce101c935ed22a626b48c2af266b84 --- Source/WebCore/rendering/RenderMarquee.cpp | 319 +++++++++++++++++++++++++++++ 1 file changed, 319 insertions(+) create mode 100644 Source/WebCore/rendering/RenderMarquee.cpp (limited to 'Source/WebCore/rendering/RenderMarquee.cpp') diff --git a/Source/WebCore/rendering/RenderMarquee.cpp b/Source/WebCore/rendering/RenderMarquee.cpp new file mode 100644 index 0000000..1c08831 --- /dev/null +++ b/Source/WebCore/rendering/RenderMarquee.cpp @@ -0,0 +1,319 @@ +/* + * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/) + * + * Portions are Copyright (C) 1998 Netscape Communications Corporation. + * + * Other contributors: + * Robert O'Callahan + * David Baron + * Christian Biesinger + * Randall Jesup + * Roland Mainz + * Josh Soref + * Boris Zbarsky + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Alternatively, the contents of this file may be used under the terms + * of either the Mozilla Public License Version 1.1, found at + * http://www.mozilla.org/MPL/ (the "MPL") or the GNU General Public + * License Version 2.0, found at http://www.fsf.org/copyleft/gpl.html + * (the "GPL"), in which case the provisions of the MPL or the GPL are + * applicable instead of those above. If you wish to allow use of your + * version of this file only under the terms of one of those two + * licenses (the MPL or the GPL) and not to allow others to use your + * version of this file under the LGPL, indicate your decision by + * deletingthe provisions above and replace them with the notice and + * other provisions required by the MPL or the GPL, as the case may be. + * If you do not delete the provisions above, a recipient may use your + * version of this file under any of the LGPL, the MPL or the GPL. + */ + +#include "config.h" + +#include "RenderMarquee.h" + +#include "FrameView.h" +#include "HTMLMarqueeElement.h" +#include "HTMLNames.h" +#include "RenderLayer.h" + +using namespace std; + +namespace WebCore { + +using namespace HTMLNames; + +RenderMarquee::RenderMarquee(RenderLayer* l) + : m_layer(l), m_currentLoop(0) + , m_totalLoops(0) + , m_timer(this, &RenderMarquee::timerFired) + , m_start(0), m_end(0), m_speed(0), m_reset(false) + , m_suspended(false), m_stopped(false), m_direction(MAUTO) +{ +} + +RenderMarquee::~RenderMarquee() +{ +} + +int RenderMarquee::marqueeSpeed() const +{ + int result = m_layer->renderer()->style()->marqueeSpeed(); + Node* n = m_layer->renderer()->node(); + if (n && n->hasTagName(marqueeTag)) { + HTMLMarqueeElement* marqueeElt = static_cast(n); + result = max(result, marqueeElt->minimumDelay()); + } + return result; +} + +EMarqueeDirection RenderMarquee::direction() const +{ + // FIXME: Support the CSS3 "auto" value for determining the direction of the marquee. + // For now just map MAUTO to MBACKWARD + EMarqueeDirection result = m_layer->renderer()->style()->marqueeDirection(); + TextDirection dir = m_layer->renderer()->style()->direction(); + if (result == MAUTO) + result = MBACKWARD; + if (result == MFORWARD) + result = (dir == LTR) ? MRIGHT : MLEFT; + if (result == MBACKWARD) + result = (dir == LTR) ? MLEFT : MRIGHT; + + // Now we have the real direction. Next we check to see if the increment is negative. + // If so, then we reverse the direction. + Length increment = m_layer->renderer()->style()->marqueeIncrement(); + if (increment.isNegative()) + result = static_cast(-result); + + return result; +} + +bool RenderMarquee::isHorizontal() const +{ + return direction() == MLEFT || direction() == MRIGHT; +} + +int RenderMarquee::computePosition(EMarqueeDirection dir, bool stopAtContentEdge) +{ + RenderBox* box = m_layer->renderBox(); + ASSERT(box); + RenderStyle* s = box->style(); + if (isHorizontal()) { + bool ltr = s->isLeftToRightDirection(); + int clientWidth = box->clientWidth(); + int contentWidth = ltr ? box->rightLayoutOverflow() : box->leftLayoutOverflow(); + if (ltr) + contentWidth += (box->paddingRight() - box->borderLeft()); + else { + contentWidth = box->width() - contentWidth; + contentWidth += (box->paddingLeft() - box->borderRight()); + } + if (dir == MRIGHT) { + if (stopAtContentEdge) + return max(0, ltr ? (contentWidth - clientWidth) : (clientWidth - contentWidth)); + else + return ltr ? contentWidth : clientWidth; + } + else { + if (stopAtContentEdge) + return min(0, ltr ? (contentWidth - clientWidth) : (clientWidth - contentWidth)); + else + return ltr ? -clientWidth : -contentWidth; + } + } + else { + int contentHeight = box->bottomLayoutOverflow() - box->borderTop() + box->paddingBottom(); + int clientHeight = box->clientHeight(); + if (dir == MUP) { + if (stopAtContentEdge) + return min(contentHeight - clientHeight, 0); + else + return -clientHeight; + } + else { + if (stopAtContentEdge) + return max(contentHeight - clientHeight, 0); + else + return contentHeight; + } + } +} + +void RenderMarquee::start() +{ + if (m_timer.isActive() || m_layer->renderer()->style()->marqueeIncrement().isZero() +#if ENABLE(WCSS) && ENABLE(XHTMLMP) + || (m_layer->renderer()->document()->isXHTMLMPDocument() && !m_layer->renderer()->style()->marqueeLoopCount()) +#endif + ) + return; + + // We may end up propagating a scroll event. It is important that we suspend events until + // the end of the function since they could delete the layer, including the marquee. + FrameView* frameView = m_layer->renderer()->document()->view(); + if (frameView) + frameView->pauseScheduledEvents(); + + if (!m_suspended && !m_stopped) { + if (isHorizontal()) + m_layer->scrollToOffset(m_start, 0, false, false); + else + m_layer->scrollToOffset(0, m_start, false, false); + } + else { + m_suspended = false; + m_stopped = false; + } + + m_timer.startRepeating(speed() * 0.001); + + if (frameView) + frameView->resumeScheduledEvents(); +} + +void RenderMarquee::suspend() +{ + m_timer.stop(); + m_suspended = true; +} + +void RenderMarquee::stop() +{ + m_timer.stop(); + m_stopped = true; +} + +void RenderMarquee::updateMarqueePosition() +{ + bool activate = (m_totalLoops <= 0 || m_currentLoop < m_totalLoops); + if (activate) { + EMarqueeBehavior behavior = m_layer->renderer()->style()->marqueeBehavior(); + m_start = computePosition(direction(), behavior == MALTERNATE); + m_end = computePosition(reverseDirection(), behavior == MALTERNATE || behavior == MSLIDE); + if (!m_stopped) + start(); + } +} + +void RenderMarquee::updateMarqueeStyle() +{ + RenderStyle* s = m_layer->renderer()->style(); + + if (m_direction != s->marqueeDirection() || (m_totalLoops != s->marqueeLoopCount() && m_currentLoop >= m_totalLoops)) + m_currentLoop = 0; // When direction changes or our loopCount is a smaller number than our current loop, reset our loop. + + m_totalLoops = s->marqueeLoopCount(); + m_direction = s->marqueeDirection(); + + if (m_layer->renderer()->isHTMLMarquee()) { + // Hack for WinIE. In WinIE, a value of 0 or lower for the loop count for SLIDE means to only do + // one loop. + if (m_totalLoops <= 0 && s->marqueeBehavior() == MSLIDE) + m_totalLoops = 1; + + // Hack alert: Set the white-space value to nowrap for horizontal marquees with inline children, thus ensuring + // all the text ends up on one line by default. Limit this hack to the element to emulate + // WinIE's behavior. Someone using CSS3 can use white-space: nowrap on their own to get this effect. + // Second hack alert: Set the text-align back to auto. WinIE completely ignores text-align on the + // marquee element. + // FIXME: Bring these up with the CSS WG. + if (isHorizontal() && m_layer->renderer()->childrenInline()) { + s->setWhiteSpace(NOWRAP); + s->setTextAlign(TAAUTO); + } + } + + // Marquee height hack!! Make sure that, if it is a horizontal marquee, the height attribute is overridden + // if it is smaller than the font size. If it is a vertical marquee and height is not specified, we default + // to a marquee of 200px. + if (isHorizontal()) { + if (s->height().isFixed() && s->height().value() < s->fontSize()) + s->setHeight(Length(s->fontSize(), Fixed)); + } else if (s->height().isAuto()) //vertical marquee with no specified height + s->setHeight(Length(200, Fixed)); + + if (speed() != marqueeSpeed()) { + m_speed = marqueeSpeed(); + if (m_timer.isActive()) + m_timer.startRepeating(speed() * 0.001); + } + + // Check the loop count to see if we should now stop. + bool activate = (m_totalLoops <= 0 || m_currentLoop < m_totalLoops); + if (activate && !m_timer.isActive()) + m_layer->renderer()->setNeedsLayout(true); + else if (!activate && m_timer.isActive()) + m_timer.stop(); +} + +void RenderMarquee::timerFired(Timer*) +{ + if (m_layer->renderer()->needsLayout()) + return; + + if (m_reset) { + m_reset = false; + if (isHorizontal()) + m_layer->scrollToXOffset(m_start); + else + m_layer->scrollToYOffset(m_start); + return; + } + + RenderStyle* s = m_layer->renderer()->style(); + + int endPoint = m_end; + int range = m_end - m_start; + int newPos; + if (range == 0) + newPos = m_end; + else { + bool addIncrement = direction() == MUP || direction() == MLEFT; + bool isReversed = s->marqueeBehavior() == MALTERNATE && m_currentLoop % 2; + if (isReversed) { + // We're going in the reverse direction. + endPoint = m_start; + range = -range; + addIncrement = !addIncrement; + } + bool positive = range > 0; + int clientSize = (isHorizontal() ? m_layer->renderBox()->clientWidth() : m_layer->renderBox()->clientHeight()); + int increment = abs(m_layer->renderer()->style()->marqueeIncrement().calcValue(clientSize)); + int currentPos = (isHorizontal() ? m_layer->scrollXOffset() : m_layer->scrollYOffset()); + newPos = currentPos + (addIncrement ? increment : -increment); + if (positive) + newPos = min(newPos, endPoint); + else + newPos = max(newPos, endPoint); + } + + if (newPos == endPoint) { + m_currentLoop++; + if (m_totalLoops > 0 && m_currentLoop >= m_totalLoops) + m_timer.stop(); + else if (s->marqueeBehavior() != MALTERNATE) + m_reset = true; + } + + if (isHorizontal()) + m_layer->scrollToXOffset(newPos); + else + m_layer->scrollToYOffset(newPos); +} + +} // namespace WebCore -- cgit v1.1