📄 render_layer.cpp
字号:
if (!buffer) buffer = new QPtrVector<RenderLayer>(); // Resize by a power of 2 when our buffer fills up. if (buffer->count() == buffer->size()) buffer->resize(2*(buffer->size()+1)); // Append ourselves at the end of the appropriate buffer. buffer->insert(buffer->count(), this); // Recur into our children to collect more layers, but only if we don't establish // a stacking context. if (!isStackingContext()) { for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) child->collectLayers(posBuffer, negBuffer); }}#ifdef ENABLE_DUMP#ifndef KDE_USE_FINALstatic QTextStream &operator<<(QTextStream &ts, const QRect &r){ return ts << "at (" << r.x() << "," << r.y() << ") size " << r.width() << "x" << r.height();}#endifstatic void write(QTextStream &ts, RenderObject& o, const QString& indent ){ o.dump(ts, indent); for (RenderObject *child = o.firstChild(); child; child = child->nextSibling()) { if (child->layer()) continue; write( ts, *child, indent + " " ); }}static void write(QTextStream &ts, const RenderLayer &l, const QRect& layerBounds, const QRect& backgroundClipRect, const QRect& clipRect, int layerType = 0, const QString& indent = QString::null){ ts << indent << "layer"; ts << " at (" << l.xPos() << "," << l.yPos() << ") size " << l.width() << "x" << l.height(); if (layerBounds != layerBounds.intersect(backgroundClipRect)) { ts << " backgroundClip " << backgroundClipRect; } if (layerBounds != layerBounds.intersect(clipRect)) { ts << " clip " << clipRect; } if (layerType == -1) ts << " layerType: background only"; else if (layerType == 1) ts << " layerType: foreground only"; ts << "\n"; if (layerType != -1) write( ts, *l.renderer(), indent + " " ); ts << "\n";}static void writeLayers(QTextStream &ts, const RenderLayer* rootLayer, RenderLayer* l, const QRect& paintDirtyRect, const QString& indent){ // Calculate the clip rects we should use. QRect layerBounds, damageRect, clipRectToApply; l->calculateRects(rootLayer, paintDirtyRect, layerBounds, damageRect, clipRectToApply); // Ensure our z-order lists are up-to-date. l->updateZOrderLists(); bool shouldPaint = l->intersectsDamageRect(layerBounds, damageRect); QPtrVector<RenderLayer>* negList = l->negZOrderList(); if (shouldPaint && negList && negList->count() > 0) write(ts, *l, layerBounds, damageRect, clipRectToApply, -1, indent); if (negList) { for (unsigned i = 0; i != negList->count(); ++i) writeLayers(ts, rootLayer, negList->at(i), paintDirtyRect, indent ); } if (shouldPaint) write(ts, *l, layerBounds, damageRect, clipRectToApply, negList && negList->count() > 0, indent); QPtrVector<RenderLayer>* posList = l->posZOrderList(); if (posList) { for (unsigned i = 0; i != posList->count(); ++i) writeLayers(ts, rootLayer, posList->at(i), paintDirtyRect, indent); }}void RenderLayer::dump(QTextStream &ts, const QString &ind){ assert( renderer()->isCanvas() ); writeLayers(ts, this, this, QRect(xPos(), yPos(), width(), height()), ind);}#endifvoid RenderLayer::styleChanged(){ if (m_object->style()->overflow() == OMARQUEE && m_object->style()->marqueeBehavior() != MNONE) { if (!m_marquee) m_marquee = new Marquee(this); m_marquee->updateMarqueeStyle(); } else if (m_marquee) { delete m_marquee; m_marquee = 0; }}void RenderLayer::suspendMarquees(){ if (m_marquee) m_marquee->suspend(); for (RenderLayer* curr = firstChild(); curr; curr = curr->nextSibling()) curr->suspendMarquees();}// --------------------------------------------------------------------------// Marquee implementationMarquee::Marquee(RenderLayer* l):m_layer(l), m_currentLoop(0), m_totalLoops(0), m_timerId(0), m_start(0), m_end(0), m_speed(0), m_unfurlPos(0), m_reset(false), m_suspended(false), m_stopped(false), m_whiteSpace(NORMAL), m_direction(MAUTO){}int Marquee::marqueeSpeed() const{ int result = m_layer->renderer()->style()->marqueeSpeed(); DOM::NodeImpl* elt = m_layer->renderer()->element(); if (elt && elt->id() == ID_MARQUEE) { HTMLMarqueeElementImpl* marqueeElt = static_cast<HTMLMarqueeElementImpl*>(elt); result = kMax(result, marqueeElt->minimumDelay()); } return result;}EMarqueeDirection Marquee::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(); EDirection 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.value() < 0) result = static_cast<EMarqueeDirection>(-result); return result;}bool Marquee::isHorizontal() const{ return direction() == MLEFT || direction() == MRIGHT;}bool Marquee::isUnfurlMarquee() const{ EMarqueeBehavior behavior = m_layer->renderer()->style()->marqueeBehavior(); return (behavior == MUNFURL);}int Marquee::computePosition(EMarqueeDirection dir, bool stopAtContentEdge){ RenderObject* o = m_layer->renderer(); RenderStyle* s = o->style(); if (isHorizontal()) { bool ltr = s->direction() == LTR; int clientWidth = o->clientWidth(); int contentWidth = ltr ? o->rightmostPosition(true, false) : o->leftmostPosition(true, false); if (ltr) contentWidth += (o->paddingRight() - o->borderLeft()); else { contentWidth = o->width() - contentWidth; contentWidth += (o->paddingLeft() - o->borderRight()); } if (dir == MRIGHT) { if (stopAtContentEdge) return kMax(0, ltr ? (contentWidth - clientWidth) : (clientWidth - contentWidth)); else return ltr ? contentWidth : clientWidth; } else { if (stopAtContentEdge) return kMin(0, ltr ? (contentWidth - clientWidth) : (clientWidth - contentWidth)); else return ltr ? -clientWidth : -contentWidth; } } else { int contentHeight = m_layer->renderer()->lowestPosition(true, false) - m_layer->renderer()->borderTop() + m_layer->renderer()->paddingBottom(); int clientHeight = m_layer->renderer()->clientHeight(); if (dir == MUP) { if (stopAtContentEdge) return kMin(contentHeight - clientHeight, 0); else return -clientHeight; } else { if (stopAtContentEdge) return kMax(contentHeight - clientHeight, 0); else return contentHeight; } }}void Marquee::start(){ if (m_timerId || m_layer->renderer()->style()->marqueeIncrement().value() == 0) return; if (!m_suspended && !m_stopped) { if (isUnfurlMarquee()) { bool forward = direction() == MDOWN || direction() == MRIGHT; bool isReversed = (forward && m_currentLoop % 2) || (!forward && !(m_currentLoop % 2)); m_unfurlPos = isReversed ? m_end : m_start; m_layer->renderer()->setChildNeedsLayout(true); } else { 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_timerId = startTimer(speed());}void Marquee::suspend(){ if (m_timerId) { killTimer(m_timerId); m_timerId = 0; } m_suspended = true;}void Marquee::stop(){ if (m_timerId) { killTimer(m_timerId); m_timerId = 0; } m_stopped = true;}void Marquee::updateMarqueePosition(){ bool activate = (m_totalLoops <= 0 || m_currentLoop < m_totalLoops); if (activate) { if (isUnfurlMarquee()) { if (m_unfurlPos < m_start) { m_unfurlPos = m_start; m_layer->renderer()->setChildNeedsLayout(true); } else if (m_unfurlPos > m_end) { m_unfurlPos = m_end; m_layer->renderer()->setChildNeedsLayout(true); } } else { 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 Marquee::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(); m_whiteSpace = s->whiteSpace(); 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 || s->marqueeBehavior() == MUNFURL)) 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 <marquee> 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); } } if (speed() != marqueeSpeed()) { m_speed = marqueeSpeed(); if (m_timerId) { killTimer(m_timerId); m_timerId = startTimer(speed()); } } // Check the loop count to see if we should now stop. bool activate = (m_totalLoops <= 0 || m_currentLoop < m_totalLoops); if (activate && !m_timerId) m_layer->renderer()->setNeedsLayout(true); else if (!activate && m_timerId) { // Destroy the timer. killTimer(m_timerId); m_timerId = 0; }}void Marquee::timerEvent(QTimerEvent* /*evt*/){ 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 (isUnfurlMarquee()) { isReversed = (!addIncrement && m_currentLoop % 2) || (addIncrement && !(m_currentLoop % 2)); addIncrement = !isReversed; } if (isReversed) { // We're going in the reverse direction. endPoint = m_start; range = -range; if (!isUnfurlMarquee()) addIncrement = !addIncrement; } bool positive = range > 0; int clientSize = isUnfurlMarquee() ? abs(range) : (isHorizontal() ? m_layer->renderer()->clientWidth() : m_layer->renderer()->clientHeight()); int increment = kMax(1, abs(m_layer->renderer()->style()->marqueeIncrement().width(clientSize))); int currentPos = isUnfurlMarquee() ? m_unfurlPos : (isHorizontal() ? m_layer->scrollXOffset() : m_layer->scrollYOffset()); newPos = currentPos + (addIncrement ? increment : -increment); if (positive) newPos = kMin(newPos, endPoint); else newPos = kMax(newPos, endPoint); } if (newPos == endPoint) { m_currentLoop++; if (m_totalLoops > 0 && m_currentLoop >= m_totalLoops) { killTimer(m_timerId); m_timerId = 0; } else if (s->marqueeBehavior() != MALTERNATE && s->marqueeBehavior() != MUNFURL) m_reset = true; } if (isUnfurlMarquee()) { m_unfurlPos = newPos; m_layer->renderer()->setChildNeedsLayout(true); } else { if (isHorizontal()) m_layer->scrollToXOffset(newPos); else m_layer->scrollToYOffset(newPos); }}#include "render_layer.moc"
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -