1 /*
2  * Copyright (C) 2003 Apple Computer, Inc.
3  *           (C) 2006 Germain Garand <germain@ebooksfrance.org>
4  *           (C) 2006 Allan Sandfeld Jense <kde@carewolf.com>
5  *
6  * Portions are Copyright (C) 1998 Netscape Communications Corporation.
7  *
8  * Other contributors:
9  *   Robert O'Callahan <roc+@cs.cmu.edu>
10  *   David Baron <dbaron@fas.harvard.edu>
11  *   Christian Biesinger <cbiesinger@web.de>
12  *   Randall Jesup <rjesup@wgate.com>
13  *   Roland Mainz <roland.mainz@informatik.med.uni-giessen.de>
14  *   Josh Soref <timeless@mac.com>
15  *   Boris Zbarsky <bzbarsky@mit.edu>
16  *
17  * This library is free software; you can redistribute it and/or
18  * modify it under the terms of the GNU Lesser General Public
19  * License as published by the Free Software Foundation; either
20  * version 2.1 of the License, or (at your option) any later version.
21  *
22  * This library is distributed in the hope that it will be useful,
23  * but WITHOUT ANY WARRANTY; without even the implied warranty of
24  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
25  * Lesser General Public License for more details.
26  *
27  * You should have received a copy of the GNU Lesser General Public
28  * License along with this library; if not, write to the Free Software
29  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
30  *
31  * Alternatively, the contents of this file may be used under the terms
32  * of either the Mozilla Public License Version 1.1, found at
33  * http://www.mozilla.org/MPL/ (the "MPL") or the GNU General Public
34  * License Version 2.0, found at http://www.fsf.org/copyleft/gpl.html
35  * (the "GPL"), in which case the provisions of the MPL or the GPL are
36  * applicable instead of those above.  If you wish to allow use of your
37  * version of this file only under the terms of one of those two
38  * licenses (the MPL or the GPL) and not to allow others to use your
39  * version of this file under the LGPL, indicate your decision by
40  * deletingthe provisions above and replace them with the notice and
41  * other provisions required by the MPL or the GPL, as the case may be.
42  * If you do not delete the provisions above, a recipient may use your
43  * version of this file under any of the LGPL, the MPL or the GPL.
44  */
45 
46 //#define BOX_DEBUG
47 
48 #include "render_layer.h"
49 #include "khtmlview.h"
50 #include "render_canvas.h"
51 #include "render_arena.h"
52 #include "render_replaced.h"
53 #include "render_form.h"
54 #include "xml/dom_docimpl.h"
55 #include "xml/dom2_eventsimpl.h"
56 #include "misc/paintbuffer.h"
57 #include "html/html_blockimpl.h"
58 #include "xml/dom_restyler.h"
59 
60 #include <QStyle>
61 #include <QStack>
62 
63 using namespace DOM;
64 using namespace khtml;
65 
66 ScrollBarWidget *RenderLayer::gScrollBar = nullptr;
67 
68 #ifndef NDEBUG
69 static bool inRenderLayerDetach;
70 #endif
71 
72 void
slotValueChanged()73 RenderScrollMediator::slotValueChanged()
74 {
75     if (m_layer->renderer()->canvas()->isPerformingLayout()) {
76         if (!m_waitingForUpdate) {
77             QTimer::singleShot(0, this, SLOT(slotValueChanged()));
78         }
79         m_waitingForUpdate = true;
80     } else {
81         m_waitingForUpdate = false;
82         m_layer->updateScrollPositionFromScrollbars();
83     }
84 }
85 
RenderLayer(RenderObject * object)86 RenderLayer::RenderLayer(RenderObject *object)
87     : m_object(object),
88       m_parent(nullptr),
89       m_previous(nullptr),
90       m_next(nullptr),
91       m_first(nullptr),
92       m_last(nullptr),
93       m_x(0),
94       m_y(0),
95       m_scrollX(0),
96       m_scrollY(0),
97       m_scrollXOrigin(0),
98       m_scrollWidth(0),
99       m_scrollHeight(0),
100       m_hBar(nullptr),
101       m_vBar(nullptr),
102       m_scrollMediator(nullptr),
103       m_posZOrderList(nullptr),
104       m_negZOrderList(nullptr),
105       m_overflowList(nullptr),
106       m_zOrderListsDirty(true),
107       m_overflowListDirty(true),
108       m_isOverflowOnly(shouldBeOverflowOnly()),
109       m_markedForRepaint(false),
110       m_hasOverlaidWidgets(false),
111       m_visibleContentStatusDirty(true),
112       m_hasVisibleContent(false),
113       m_visibleDescendantStatusDirty(false),
114       m_hasVisibleDescendant(false),
115       m_inScrollbarRelayout(false),
116       m_marquee(nullptr)
117 {
118     if (!object->firstChild() && object->style()) {
119         m_visibleContentStatusDirty = false;
120         m_hasVisibleContent = object->style()->visibility() == VISIBLE;
121     }
122     m_buffer[0] = nullptr;
123     m_buffer[1] = nullptr;
124     m_wasStackingContext = object->style() ? isStackingContext() : false;
125 }
126 
~RenderLayer()127 RenderLayer::~RenderLayer()
128 {
129     // Child layers will be deleted by their corresponding render objects, so
130     // our destructor doesn't have to do anything.
131     delete m_hBar;
132     delete m_vBar;
133     delete m_buffer[0];
134     delete m_buffer[1];
135     delete m_scrollMediator;
136     delete m_posZOrderList;
137     delete m_negZOrderList;
138     delete m_overflowList;
139     delete m_marquee;
140 }
141 
updateLayerPosition()142 void RenderLayer::updateLayerPosition()
143 {
144 
145     // The canvas is sized to the docWidth/Height over in RenderCanvas::layout, so we
146     // don't need to ever update our layer position here.
147     if (renderer()->isCanvas()) {
148         return;
149     }
150 
151     int x = m_object->xPos();
152     int y = m_object->yPos() - m_object->borderTopExtra();
153 
154     if (!m_object->isPositioned()) {
155         // We must adjust our position by walking up the render tree looking for the
156         // nearest enclosing object with a layer.
157         RenderObject *curr = m_object->parent();
158         while (curr && !curr->layer()) {
159             x += curr->xPos();
160             y += curr->yPos();
161             curr = curr->parent();
162         }
163         if (curr) {
164             y += curr->borderTopExtra();
165         }
166     }
167 
168     if (m_object->isRelPositioned()) {
169         static_cast<RenderBox *>(m_object)->relativePositionOffset(x, y);
170     }
171 
172     // Subtract our parent's scroll offset.
173     if (m_object->isPositioned() && enclosingPositionedAncestor()) {
174         RenderLayer *positionedParent = enclosingPositionedAncestor();
175 
176         // For positioned layers, we subtract out the enclosing positioned layer's scroll offset.
177         positionedParent->subtractScrollOffset(x, y);
178         positionedParent->checkInlineRelOffset(m_object, x, y);
179     } else if (parent()) {
180         parent()->subtractScrollOffset(x, y);
181     }
182 
183     setPos(x, y);
184 }
185 
paintedRegion(RenderLayer * rootLayer)186 QRegion RenderLayer::paintedRegion(RenderLayer *rootLayer)
187 {
188     updateZOrderLists();
189     QRegion r;
190     const RenderStyle *s = renderer()->style();
191     bool isTrans = (s->opacity() < 1.0);
192     if (isTrans && m_hasVisibleDescendant) {
193         if (!s->opacity()) {
194             return r;
195         }
196         for (RenderLayer *ch = firstChild(); ch; ch = ch->nextSibling()) {
197             r += ch->paintedRegion(rootLayer);
198         }
199     } else if (m_negZOrderList && m_hasVisibleDescendant) {
200         uint count = m_negZOrderList->count();
201         for (uint i = 0; i < count; i++) {
202             RenderLayer *child = m_negZOrderList->at(i);
203             r += child->paintedRegion(rootLayer);
204         }
205     }
206 
207     if (m_hasVisibleContent) {
208         int x = 0; int y = 0;
209         convertToLayerCoords(rootLayer, x, y);
210         QRect cr(x, y, width(), height());
211         if (s->visibility() == VISIBLE && (s->backgroundImage() || s->backgroundColor().isValid() || s->hasBorder() ||
212                                            renderer()->scrollsOverflow() || renderer()->isReplaced())) {
213             if (!s->hidesOverflow()) {
214                 r += renderer()->visibleFlowRegion(x, y);
215             }
216             r += cr;
217         } else {
218             r += renderer()->visibleFlowRegion(x, y);
219         }
220     }
221 
222     if (!isTrans && m_posZOrderList && m_hasVisibleDescendant) {
223         uint count = m_posZOrderList->count();
224         for (uint i = 0; i < count; i++) {
225             RenderLayer *child = m_posZOrderList->at(i);
226             r += child->paintedRegion(rootLayer);
227         }
228     }
229     return r;
230 }
231 
repaint(Priority p,bool markForRepaint)232 void RenderLayer::repaint(Priority p, bool markForRepaint)
233 {
234     if (markForRepaint && m_markedForRepaint) {
235         return;
236     }
237     for (RenderLayer *child = firstChild(); child; child = child->nextSibling()) {
238         child->repaint(p, markForRepaint);
239     }
240     QRect layerBounds, damageRect, fgrect;
241     calculateRects(renderer()->canvas()->layer(), renderer()->viewRect(), layerBounds, damageRect, fgrect);
242     m_visibleRect = damageRect.intersected(layerBounds);
243     if (m_visibleRect.isValid()) {
244         renderer()->canvas()->repaintViewRectangle(m_visibleRect.x(), m_visibleRect.y(), m_visibleRect.width(), m_visibleRect.height(), (p > NormalPriority));
245     }
246     if (markForRepaint) {
247         m_markedForRepaint = true;
248     }
249 }
250 
updateLayerPositions(RenderLayer * rootLayer,bool doFullRepaint,bool checkForRepaint)251 void RenderLayer::updateLayerPositions(RenderLayer *rootLayer, bool doFullRepaint, bool checkForRepaint)
252 {
253     if (doFullRepaint) {
254         m_object->repaint();
255         checkForRepaint = doFullRepaint = false;
256     }
257 
258     updateLayerPosition(); // For relpositioned layers or non-positioned layers,
259     // we need to keep in sync, since we may have shifted relative
260     // to our parent layer.
261 
262     if (m_hBar || m_vBar) {
263         // Need to position the scrollbars.
264         int x = 0;
265         int y = 0;
266         convertToLayerCoords(rootLayer, x, y);
267         QRect layerBounds = QRect(x, y, width(), height());
268         positionScrollbars(layerBounds);
269     }
270 
271     updateVisibilityStatus();
272 
273     if (m_hasVisibleContent && checkForRepaint && m_markedForRepaint) {
274         QRect layerBounds, damageRect, fgrect;
275         calculateRects(rootLayer, renderer()->viewRect(), layerBounds, damageRect, fgrect);
276         QRect vr = damageRect.intersected(layerBounds);
277         if (vr != m_visibleRect && vr.isValid()) {
278             renderer()->canvas()->repaintViewRectangle(vr.x(), vr.y(), vr.width(), vr.height());
279             m_visibleRect = vr;
280         }
281     }
282     m_markedForRepaint = false;
283 
284     for (RenderLayer *child = firstChild(); child; child = child->nextSibling()) {
285         child->updateLayerPositions(rootLayer, doFullRepaint, checkForRepaint);
286     }
287 
288     // With all our children positioned, now update our marquee if we need to.
289     if (m_marquee) {
290         m_marquee->updateMarqueePosition();
291     }
292 }
293 
setHasVisibleContent(bool b)294 void RenderLayer::setHasVisibleContent(bool b)
295 {
296     if (m_hasVisibleContent == b && !m_visibleContentStatusDirty) {
297         return;
298     }
299     m_visibleContentStatusDirty = false;
300     m_hasVisibleContent = b;
301     if (m_hasVisibleContent) {
302         // ### dirty painted region
303         // m_region = QRegion();
304         if (!isOverflowOnly())
305             if (RenderLayer *sc = stackingContext()) {
306                 sc->dirtyZOrderLists();
307             }
308     }
309     if (parent()) {
310         parent()->childVisibilityChanged(m_hasVisibleContent);
311     }
312 }
313 
dirtyVisibleContentStatus()314 void RenderLayer::dirtyVisibleContentStatus()
315 {
316     m_visibleContentStatusDirty = true;
317     if (parent()) {
318         parent()->dirtyVisibleDescendantStatus();
319     }
320 }
321 
childVisibilityChanged(bool newVisibility)322 void RenderLayer::childVisibilityChanged(bool newVisibility)
323 {
324     if (m_hasVisibleDescendant == newVisibility || m_visibleDescendantStatusDirty) {
325         return;
326     }
327     if (newVisibility) {
328         RenderLayer *l = this;
329         while (l && !l->m_visibleDescendantStatusDirty && !l->m_hasVisibleDescendant) {
330             l->m_hasVisibleDescendant = true;
331             l = l->parent();
332         }
333     } else {
334         dirtyVisibleDescendantStatus();
335     }
336 }
337 
dirtyVisibleDescendantStatus()338 void RenderLayer::dirtyVisibleDescendantStatus()
339 {
340     RenderLayer *l = this;
341     while (l && !l->m_visibleDescendantStatusDirty) {
342         l->m_visibleDescendantStatusDirty = true;
343         l = l->parent();
344     }
345 }
346 
updateVisibilityStatus()347 void RenderLayer::updateVisibilityStatus()
348 {
349     if (m_visibleDescendantStatusDirty) {
350         m_hasVisibleDescendant = false;
351         for (RenderLayer *child = firstChild(); child; child = child->nextSibling()) {
352             child->updateVisibilityStatus();
353             if (child->m_hasVisibleContent || child->m_hasVisibleDescendant) {
354                 m_hasVisibleDescendant = true;
355                 break;
356             }
357         }
358         m_visibleDescendantStatusDirty = false;
359     }
360 
361     if (m_visibleContentStatusDirty) {
362         if (m_object->style()->visibility() == VISIBLE) {
363             m_hasVisibleContent = true;
364         } else {
365             // layer may be hidden but still have some visible content, check for this
366             m_hasVisibleContent = false;
367             RenderObject *r = m_object->firstChild();
368             while (r) {
369                 if (r->style()->visibility() == VISIBLE && !r->layer()) {
370                     m_hasVisibleContent = true;
371                     break;
372                 }
373                 if (r->firstChild() && !r->layer()) {
374                     r = r->firstChild();
375                 } else if (r->nextSibling()) {
376                     r = r->nextSibling();
377                 } else {
378                     do {
379                         r = r->parent();
380                         if (r == m_object) {
381                             r = nullptr;
382                         }
383                     } while (r && !r->nextSibling());
384                     if (r) {
385                         r = r->nextSibling();
386                     }
387                 }
388             }
389         }
390         m_visibleContentStatusDirty = false;
391     }
392 }
393 
updateWidgetMasks(RenderLayer * rootLayer)394 void RenderLayer::updateWidgetMasks(RenderLayer *rootLayer)
395 {
396     if (hasOverlaidWidgets() && !renderer()->canvas()->pagedMode()) {
397         updateZOrderLists();
398         uint count = m_posZOrderList ? m_posZOrderList->count() : 0;
399         bool needUpdate = false;
400         KHTMLView *sa = nullptr;
401         if (count > 0) {
402             sa = m_object->document()->view();
403             m_region = QRect(0, 0, sa->contentsWidth(), sa->contentsHeight());
404             for (uint i = 0; i < count; i++) {
405                 RenderLayer *child = m_posZOrderList->at(i);
406                 if (child->zIndex() == 0 && child->renderer()->style()->position() == PSTATIC) {
407                     continue;    // we don't know the widget's exact stacking position within flow
408                 }
409                 m_region -= child->paintedRegion(rootLayer);
410             }
411             needUpdate = true;
412         }
413         RenderLayer *sc = this;
414         int zx = zIndex();
415         while ((sc = sc->stackingContext())) {
416             sc->updateZOrderLists();
417             bool found = false;
418             if (zx < 0) {
419                 count = sc->m_negZOrderList ? sc->m_negZOrderList->count() : 0;
420                 needUpdate = needUpdate || count > 0;
421                 for (uint i = 0; i < count; i++) {
422                     found = found || sc->m_negZOrderList->at(i)->zIndex() > zx;
423                     if (found) {
424                         if (!sa) {
425                             sa = m_object->document()->view();
426                             m_region = QRect(0, 0, sa->contentsWidth(), sa->contentsHeight());
427                         }
428                         m_region -= sc->m_negZOrderList->at(i)->paintedRegion(rootLayer);
429                     }
430                 }
431             }
432             count = sc->m_posZOrderList ? sc->m_posZOrderList->count() : 0;
433             if (count > 0) {
434                 needUpdate = true;
435                 for (uint i = 0; i < count; i++) {
436                     found = found || sc->m_posZOrderList->at(i)->zIndex() > zx;
437                     if (found) {
438                         if (!sa) {
439                             sa = m_object->document()->view();
440                             m_region = QRect(0, 0, sa->contentsWidth(), sa->contentsHeight());
441                         }
442                         m_region -= sc->m_posZOrderList->at(i)->paintedRegion(rootLayer);
443                     }
444                 }
445             }
446             zx = sc->zIndex();
447         }
448         if (!needUpdate) {
449             needUpdate = !m_region.isEmpty();
450             m_region = QRegion();
451         }
452         if (needUpdate) {
453             renderer()->updateWidgetMasks();
454         }
455     }
456     for (RenderLayer *child = firstChild(); child; child = child->nextSibling()) {
457         child->updateWidgetMasks(rootLayer);
458     }
459 }
460 
width() const461 int RenderLayer::width() const
462 {
463     int w = m_object->width();
464     if (!m_object->hasOverflowClip()) {
465         w = qMax(m_object->overflowWidth(), w);
466     }
467     return w;
468 }
469 
height() const470 int RenderLayer::height() const
471 {
472     int h = m_object->height() + m_object->borderTopExtra() + m_object->borderBottomExtra();
473     if (!m_object->hasOverflowClip()) {
474         h = qMax(m_object->overflowHeight(), h);
475     }
476     return h;
477 }
478 
stackingContext() const479 RenderLayer *RenderLayer::stackingContext() const
480 {
481     RenderLayer *curr = parent();
482     for (; curr && !curr->m_object->isCanvas() &&
483             curr->m_object->style()->hasAutoZIndex();
484             curr = curr->parent()) {};
485     return curr;
486 }
487 
enclosingPositionedAncestor() const488 RenderLayer *RenderLayer::enclosingPositionedAncestor() const
489 {
490     RenderLayer *curr = parent();
491     for (; curr && !curr->m_object->isCanvas() &&
492             !curr->m_object->isPositioned() && !curr->m_object->isRelPositioned();
493             curr = curr->parent()) {};
494 
495     return curr;
496 }
497 
isTransparent() const498 bool RenderLayer::isTransparent() const
499 {
500     return m_object->style()->opacity() < 1.0f;
501 }
502 
transparentAncestor() const503 RenderLayer *RenderLayer::transparentAncestor() const
504 {
505     RenderLayer *curr = parent();
506     for (; curr && curr->m_object->style()->opacity() == 1.0f; curr = curr->parent()) {};
507     return curr;
508 }
509 
operator new(size_t sz,RenderArena * renderArena)510 void *RenderLayer::operator new(size_t sz, RenderArena *renderArena) throw()
511 {
512     return renderArena->allocate(sz);
513 }
514 
operator delete(void * ptr,size_t sz)515 void RenderLayer::operator delete(void *ptr, size_t sz)
516 {
517     assert(inRenderLayerDetach);
518 #ifdef KHTML_USE_ARENA_ALLOCATOR
519     // Stash size where detach can find it.
520     *(size_t *)ptr = sz;
521 #endif
522 }
523 
detach(RenderArena * renderArena)524 void RenderLayer::detach(RenderArena *renderArena)
525 {
526 #ifndef NDEBUG
527     inRenderLayerDetach = true;
528 #endif
529     delete this;
530 #ifndef NDEBUG
531     inRenderLayerDetach = false;
532 #endif
533 
534     // Recover the size left there for us by operator delete and free the memory.
535     renderArena->free(*(size_t *)this, this);
536 }
537 
addChild(RenderLayer * child,RenderLayer * beforeChild)538 void RenderLayer::addChild(RenderLayer *child, RenderLayer *beforeChild)
539 {
540     RenderLayer *prevSibling = beforeChild ? beforeChild->previousSibling() : lastChild();
541     if (prevSibling) {
542         child->setPreviousSibling(prevSibling);
543         prevSibling->setNextSibling(child);
544     } else {
545         setFirstChild(child);
546     }
547 
548     if (beforeChild) {
549         beforeChild->setPreviousSibling(child);
550         child->setNextSibling(beforeChild);
551     } else {
552         setLastChild(child);
553     }
554 
555     child->setParent(this);
556 
557     if (child->isOverflowOnly()) {
558         dirtyOverflowList();
559     } else {
560         // Dirty the z-order list in which we are contained.  The stackingContext() can be null in the
561         // case where we're building up generated content layers.  This is ok, since the lists will start
562         // off dirty in that case anyway.
563         RenderLayer *stackingContext = child->stackingContext();
564         if (stackingContext) {
565             stackingContext->dirtyZOrderLists();
566         }
567     }
568     child->updateVisibilityStatus();
569     if (child->m_hasVisibleContent || child->m_hasVisibleDescendant) {
570         childVisibilityChanged(true);
571     }
572 }
573 
removeChild(RenderLayer * oldChild)574 RenderLayer *RenderLayer::removeChild(RenderLayer *oldChild)
575 {
576     // remove the child
577     if (oldChild->previousSibling()) {
578         oldChild->previousSibling()->setNextSibling(oldChild->nextSibling());
579     }
580     if (oldChild->nextSibling()) {
581         oldChild->nextSibling()->setPreviousSibling(oldChild->previousSibling());
582     }
583 
584     if (m_first == oldChild) {
585         m_first = oldChild->nextSibling();
586     }
587     if (m_last == oldChild) {
588         m_last = oldChild->previousSibling();
589     }
590 
591     if (oldChild->isOverflowOnly()) {
592         dirtyOverflowList();
593     } else {
594         // Dirty the z-order list in which we are contained.  When called via the
595         // reattachment process in removeOnlyThisLayer, the layer may already be disconnected
596         // from the main layer tree, so we need to null-check the |stackingContext| value.
597         RenderLayer *stackingContext = oldChild->stackingContext();
598         if (stackingContext) {
599             stackingContext->dirtyZOrderLists();
600         }
601     }
602 
603     oldChild->setPreviousSibling(nullptr);
604     oldChild->setNextSibling(nullptr);
605     oldChild->setParent(nullptr);
606 
607     oldChild->updateVisibilityStatus();
608     if (oldChild->m_hasVisibleContent || oldChild->m_hasVisibleDescendant) {
609         childVisibilityChanged(false);
610     }
611 
612     return oldChild;
613 }
614 
removeOnlyThisLayer()615 void RenderLayer::removeOnlyThisLayer()
616 {
617     if (!m_parent) {
618         return;
619     }
620 
621     // Remove us from the parent.
622     RenderLayer *parent = m_parent;
623     RenderLayer *nextSib = nextSibling();
624     parent->removeChild(this);
625 
626     // Now walk our kids and reattach them to our parent.
627     RenderLayer *current = m_first;
628     while (current) {
629         RenderLayer *next = current->nextSibling();
630         removeChild(current);
631         parent->addChild(current, nextSib);
632         current = next;
633     }
634 
635     detach(renderer()->renderArena());
636 }
637 
insertOnlyThisLayer()638 void RenderLayer::insertOnlyThisLayer()
639 {
640     if (!m_parent && renderer()->parent()) {
641         // We need to connect ourselves when our renderer() has a parent.
642         // Find our enclosingLayer and add ourselves.
643         RenderLayer *parentLayer = renderer()->parent()->enclosingLayer();
644         if (parentLayer)
645             parentLayer->addChild(this,
646                                   renderer()->parent()->findNextLayer(parentLayer, renderer()));
647     }
648 
649     // Remove all descendant layers from the hierarchy and add them to the new position.
650     for (RenderObject *curr = renderer()->firstChild(); curr; curr = curr->nextSibling()) {
651         curr->moveLayers(m_parent, this);
652     }
653 }
654 
convertToLayerCoords(const RenderLayer * ancestorLayer,int & x,int & y) const655 void RenderLayer::convertToLayerCoords(const RenderLayer *ancestorLayer, int &x, int &y) const
656 {
657     if (ancestorLayer == this) {
658         return;
659     }
660 
661     if (m_object->style()->position() == PFIXED) {
662         // Add in the offset of the view.  We can obtain this by calling
663         // absolutePosition() on the RenderCanvas.
664         int xOff, yOff;
665         m_object->absolutePosition(xOff, yOff, true);
666         x += xOff;
667         y += yOff;
668         return;
669     }
670 
671     RenderLayer *parentLayer;
672     if (m_object->style()->position() == PABSOLUTE) {
673         parentLayer = enclosingPositionedAncestor();
674     } else {
675         parentLayer = parent();
676     }
677 
678     if (!parentLayer) {
679         return;
680     }
681 
682     parentLayer->convertToLayerCoords(ancestorLayer, x, y);
683 
684     x += xPos();
685     y += yPos();
686 }
687 
scrollOffset(int & x,int & y)688 void RenderLayer::scrollOffset(int &x, int &y)
689 {
690     x += scrollXOffset();
691     y += scrollYOffset();
692 }
693 
subtractScrollOffset(int & x,int & y)694 void RenderLayer::subtractScrollOffset(int &x, int &y)
695 {
696     x -= scrollXOffset();
697     y -= scrollYOffset();
698 }
699 
checkInlineRelOffset(const RenderObject * o,int & x,int & y)700 void RenderLayer::checkInlineRelOffset(const RenderObject *o, int &x, int &y)
701 {
702     if (o->style()->position() != PABSOLUTE || !renderer()->isRelPositioned() || !renderer()->isInlineFlow()) {
703         return;
704     }
705 
706     // Our renderer is an enclosing relpositioned inline, we need to add in the offset of the first line
707     // box from the rest of the content, but only in the cases where we know our descendant is positioned
708     // relative to the inline itself.
709     assert(o->container() == m_object);
710 
711     RenderFlow *flow = static_cast<RenderFlow *>(m_object);
712     int sx = 0, sy = 0;
713     if (flow->firstLineBox()) {
714         if (flow->style()->direction() == LTR) {
715             sx = flow->firstLineBox()->xPos();
716         } else {
717             sx = flow->lastLineBox()->xPos();
718         }
719         sy = flow->firstLineBox()->yPos();
720     } else {
721         sx = flow->staticX(); // ###
722         sy = flow->staticY();
723     }
724     bool isInlineType = o->style()->isOriginalDisplayInlineType();
725 
726     if (!o->hasStaticX()) {
727         x += sx;
728     }
729 
730     // Despite the positioned child being a block display type inside an inline, we still keep
731     // its x locked to our left.  Arguably the correct behavior would be to go flush left to
732     // the block that contains us, but that isn't what other browsers do.
733     if (o->hasStaticX() && !isInlineType)
734         // Avoid adding in the left border/padding of the containing block twice.  Subtract it out.
735     {
736         x += sx - (o->containingBlock()->borderLeft() + o->containingBlock()->paddingLeft());
737     }
738 
739     if (!o->hasStaticY()) {
740         y += sy;
741     }
742 }
743 
scrollToOffset(int x,int y,bool updateScrollbars,bool repaint,bool dispatchEvent)744 void RenderLayer::scrollToOffset(int x, int y, bool updateScrollbars, bool repaint, bool dispatchEvent)
745 {
746     assert(!renderer()->canvas()->isPerformingLayout() || !dispatchEvent);
747     if (renderer()->style()->overflowX() != OMARQUEE || !renderer()->hasOverflowClip()) {
748         if (x < 0) {
749             x = 0;
750         }
751         if (y < 0) {
752             y = 0;
753         }
754 
755         // Call the scrollWidth/Height functions so that the dimensions will be computed if they need
756         // to be (for overflow:hidden blocks).
757         // ### merge the scrollWidth()/scrollHeight() methods
758         int maxX = m_scrollWidth - m_object->clientWidth();
759         int maxY = m_scrollHeight - m_object->clientHeight();
760 
761         if (x > maxX) {
762             x = maxX;
763         }
764         if (y > maxY) {
765             y = maxY;
766         }
767     }
768 
769     if ((m_scrollX == x - m_scrollXOrigin) && m_scrollY == y) {
770         return;    // nothing to do
771     }
772 
773     // FIXME: Eventually, we will want to perform a blit.  For now never
774     // blit, since the check for blitting is going to be very
775     // complicated (since it will involve testing whether our layer
776     // is either occluded by another layer or clipped by an enclosing
777     // layer or contains fixed backgrounds, etc.).
778     m_scrollX = x - m_scrollXOrigin;
779     m_scrollY = y;
780 
781     // Update the positions of our child layers.
782     RenderLayer *rootLayer = root();
783     for (RenderLayer *child = firstChild(); child; child = child->nextSibling()) {
784         child->updateLayerPositions(rootLayer);
785     }
786 
787     // Just schedule a full repaint of our object.
788     if (repaint) {
789         m_object->repaint(RealtimePriority);
790     }
791 
792     if (updateScrollbars) {
793         if (m_hBar) {
794             m_hBar->setValue(scrollXOffset());
795         }
796         if (m_vBar) {
797             m_vBar->setValue(m_scrollY);
798         }
799     }
800 
801     if (!dispatchEvent) {
802         return;
803     }
804 
805     // Fire the scroll DOM event. Do this the very last thing, since the handler may kill us.
806     m_object->element()->dispatchHTMLEvent(EventImpl::SCROLL_EVENT, false, false);
807 }
808 
updateScrollPositionFromScrollbars()809 void RenderLayer::updateScrollPositionFromScrollbars()
810 {
811     bool needUpdate = false;
812     int newX = m_scrollX;
813     int newY = m_scrollY;
814 
815     if (m_hBar) {
816         bool rtl = (m_hBar->layoutDirection() == Qt::RightToLeft);
817         newX = rtl ? m_hBar->maximum() - m_hBar->value() : m_hBar->value();
818         if (newX != m_scrollX) {
819             needUpdate = true;
820         }
821     }
822 
823     if (m_vBar) {
824         newY = m_vBar->value();
825         if (newY != m_scrollY) {
826             needUpdate = true;
827         }
828     }
829 
830     if (needUpdate) {
831         scrollToOffset(newX, newY, false);
832     }
833 }
834 
835 void
showScrollbar(Qt::Orientation o,bool show)836 RenderLayer::showScrollbar(Qt::Orientation o, bool show)
837 {
838     ScrollBarWidget *sb = (o == Qt::Horizontal) ? m_hBar : m_vBar;
839 
840     if (show && !sb) {
841         KHTMLView *view = m_object->document()->view();
842         sb = new ScrollBarWidget(o, view->widget());
843         sb->move(0, -50000);
844         sb->setAttribute(Qt::WA_NoSystemBackground);
845         sb->show();
846         if (!m_scrollMediator) {
847             m_scrollMediator = new RenderScrollMediator(this);
848         }
849         m_scrollMediator->connect(sb, SIGNAL(valueChanged(int)), SLOT(slotValueChanged()));
850     } else if (!show && sb) {
851         delete sb;
852         sb = nullptr;
853     }
854 
855     if (o == Qt::Horizontal) {
856         m_hBar = sb;
857     } else {
858         m_vBar = sb;
859     }
860 }
861 
hasReversedScrollbar() const862 bool RenderLayer::hasReversedScrollbar() const
863 {
864     if (!m_vBar) {
865         return false;
866     }
867     return (m_vBar->layoutDirection() == Qt::RightToLeft);
868 }
869 
verticalScrollbarWidth()870 int RenderLayer::verticalScrollbarWidth()
871 {
872     if (!m_vBar) {
873         return 0;
874     }
875 
876 #ifdef APPLE_CHANGES
877     return m_vBar->width();
878 #else
879     return m_vBar->style()->pixelMetric(QStyle::PM_ScrollBarExtent);
880 #endif
881 
882 }
883 
horizontalScrollbarHeight()884 int RenderLayer::horizontalScrollbarHeight()
885 {
886     if (!m_hBar) {
887         return 0;
888     }
889 
890 #ifdef APPLE_CHANGES
891     return m_hBar->height();
892 #else
893     return m_hBar->style()->pixelMetric(QStyle::PM_ScrollBarExtent);
894 #endif
895 
896 }
897 
positionScrollbars(const QRect & absBounds)898 void RenderLayer::positionScrollbars(const QRect &absBounds)
899 {
900 #ifdef APPLE_CHANGES
901     if (m_vBar) {
902         view->addChild(m_vBar, absBounds.x() + absBounds.width() - m_object->borderRight() - m_vBar->width(),
903                        absBounds.y() + m_object->borderTop());
904         m_vBar->resize(m_vBar->width(), absBounds.height() -
905                        (m_object->borderTop() + m_object->borderBottom()) -
906                        (m_hBar ? m_hBar->height() - 1 : 0));
907     }
908 
909     if (m_hBar) {
910         view->addChild(m_hBar, absBounds.x() + m_object->borderLeft(),
911                        absBounds.y() + absBounds.height() - m_object->borderBottom() - m_hBar->height());
912         m_hBar->resize(absBounds.width() - (m_object->borderLeft() + m_object->borderRight()) -
913                        (m_vBar ? m_vBar->width() - 1 : 0), m_hBar->height());
914     }
915 #else
916     int tx = absBounds.x();
917     int ty = absBounds.y();
918     int bl = m_object->borderLeft();
919     int bt = m_object->borderTop();
920     int w = width() - bl - m_object->borderRight();
921     int h = height() - bt - m_object->borderBottom();
922 
923     if (w <= 0 || h <= 0 || (!m_vBar && !m_hBar)) {
924         return;
925     }
926 
927     tx += bl;
928     ty += bt;
929 
930     ScrollBarWidget *b = m_hBar;
931     if (!m_hBar) {
932         b = m_vBar;
933     }
934     int sw = b->style()->pixelMetric(QStyle::PM_ScrollBarExtent);
935     bool rtl = b->layoutDirection() == Qt::RightToLeft;
936 
937     if (m_vBar) {
938         QRect vBarRect = QRect(tx + (rtl ? 0 : w - sw), ty, sw, h - (m_hBar ? sw : 0));
939         m_vBar->resize(vBarRect.width(), vBarRect.height());
940         m_vBar->m_kwp->setPos(QPoint(vBarRect.x(), vBarRect.y()));
941     }
942 
943     if (m_hBar) {
944         QRect hBarRect = QRect(tx + (rtl && m_vBar ? sw : 0), ty + h - sw, w - (!rtl && m_vBar ? sw : 0), sw);
945         m_hBar->resize(hBarRect.width(), hBarRect.height());
946         m_hBar->m_kwp->setPos(QPoint(hBarRect.x(), hBarRect.y()));
947     }
948 #endif
949 }
950 
951 #define LINE_STEP   10
952 #define PAGE_KEEP   40
953 
checkScrollbarsAfterLayout()954 void RenderLayer::checkScrollbarsAfterLayout()
955 {
956     int rightPos = m_object->rightmostPosition(true);
957     int bottomPos = m_object->lowestPosition(true);
958 
959     /*  TODO
960         m_scrollLeft = m_object->leftmostPosition(true);
961         m_scrollTop = m_object->highestPosition(true);
962     */
963 
964     int clientWidth = m_object->clientWidth();
965     int clientHeight = m_object->clientHeight();
966     m_scrollWidth = clientWidth;
967     m_scrollHeight = clientHeight;
968 
969     if (rightPos - m_object->borderLeft() > m_scrollWidth) {
970         m_scrollWidth = rightPos - m_object->borderLeft();
971     }
972     if (bottomPos - m_object->borderTop() > m_scrollHeight) {
973         m_scrollHeight = bottomPos - m_object->borderTop();
974     }
975 
976     m_scrollXOrigin = 0; // ### (m_object->style()->direction() == RTL) ? m_scrollWidth - clientWidth : 0;
977 
978     bool needHorizontalBar = rightPos > width();
979     bool needVerticalBar = bottomPos > height();
980 
981     bool haveHorizontalBar = m_hBar && m_hBar->isEnabled();
982     bool haveVerticalBar = m_vBar && m_vBar->isEnabled();
983 
984     bool hasOvf = m_object->hasOverflowClip();
985 
986     // overflow:scroll should just enable/disable.
987     if (m_hBar && hasOvf && m_object->style()->overflowX() == OSCROLL) {
988         m_hBar->setEnabled(needHorizontalBar);
989     }
990     if (m_vBar && hasOvf && m_object->style()->overflowY() == OSCROLL) {
991         m_vBar->setEnabled(needVerticalBar);
992     }
993 
994     // Sometimes we originally had a scrolling overflow, but it got changed to
995     // hidden/visible.
996     bool deadScrollX = m_hBar && !m_object->scrollsOverflowX();
997     bool deadScrollY = m_vBar && !m_object->scrollsOverflowY();
998 
999     // overflow:auto may need to lay out again if scrollbars got added/removed.
1000     // Also remove now useless scrollbars for non-scrollable overflows
1001     bool scrollbarsChanged = (hasOvf && m_object->style()->overflowX() == OAUTO && haveHorizontalBar != needHorizontalBar)
1002                              || (hasOvf && m_object->style()->overflowY() == OAUTO && haveVerticalBar != needVerticalBar)
1003                              || deadScrollX || deadScrollY;
1004     if (scrollbarsChanged && !m_inScrollbarRelayout) {
1005         if (m_object->style()->overflowX() == OAUTO) {
1006             showScrollbar(Qt::Horizontal, needHorizontalBar);
1007             if (m_hBar) {
1008                 m_hBar->setEnabled(true);
1009             } else {
1010                 resetXOffset();
1011             }
1012         }
1013         if (m_object->style()->overflowY() == OAUTO) {
1014             showScrollbar(Qt::Vertical, needVerticalBar);
1015             if (m_vBar) {
1016                 m_vBar->setEnabled(true);
1017             } else {
1018                 resetYOffset();
1019             }
1020         }
1021 
1022         if (deadScrollX) {
1023             showScrollbar(Qt::Horizontal, false);
1024             resetXOffset();
1025         }
1026 
1027         if (deadScrollY) {
1028             showScrollbar(Qt::Vertical, false);
1029             resetYOffset();
1030         }
1031 
1032         m_object->setNeedsLayout(true);
1033         m_inScrollbarRelayout = true;
1034         if (m_object->isRenderBlock()) {
1035             static_cast<RenderBlock *>(m_object)->layoutBlock(true);
1036         } else {
1037             m_object->layout();
1038         }
1039         m_inScrollbarRelayout = false;
1040         return;
1041     }
1042 
1043     m_inScrollbarRelayout = false;
1044 
1045     // Set up the range (and page step/line step).
1046     if (m_hBar) {
1047         int pageStep = (clientWidth - PAGE_KEEP);
1048         if (pageStep < 0) {
1049             pageStep = clientWidth;
1050         }
1051         m_hBar->setSingleStep(LINE_STEP);
1052         m_hBar->setPageStep(pageStep);
1053         m_hBar->setRange(0, needHorizontalBar ? m_scrollWidth - clientWidth : 0);
1054         if (hasReversedScrollbar()) {
1055             m_hBar->setValue(m_hBar->maximum() - m_scrollX);
1056         }
1057     }
1058     if (m_vBar) {
1059         int pageStep = (clientHeight - PAGE_KEEP);
1060         if (pageStep < 0) {
1061             pageStep = clientHeight;
1062         }
1063         m_vBar->setSingleStep(LINE_STEP);
1064         m_vBar->setPageStep(pageStep);
1065         m_vBar->setRange(0, needVerticalBar ? m_scrollHeight - clientHeight : 0);
1066     }
1067 }
1068 
paintScrollbars(RenderObject::PaintInfo & pI)1069 void RenderLayer::paintScrollbars(RenderObject::PaintInfo &pI)
1070 {
1071     if (!m_object->element()) {
1072         return;
1073     }
1074 
1075     if (m_hBar) {
1076         if (!m_buffer[0] || m_buffer[0]->size() != m_hBar->size()) {
1077             delete m_buffer[0];
1078             m_buffer[0] = new QPixmap(m_hBar->size());
1079         }
1080         QPoint p = m_hBar->m_kwp->absolutePos();
1081         RenderWidget::paintWidget(pI, m_hBar, p.x(), p.y(), m_buffer);
1082     }
1083     if (m_vBar) {
1084         if (!m_buffer[1] || m_buffer[1]->size() != m_vBar->size()) {
1085             delete m_buffer[1];
1086             m_buffer[1] = new QPixmap(m_vBar->size());
1087         }
1088         QPixmap *tmp[1];
1089         tmp[0] = m_buffer[1];
1090         QPoint p = m_vBar->m_kwp->absolutePos();
1091         RenderWidget::paintWidget(pI, m_vBar, p.x(), p.y(), tmp);
1092     }
1093 }
1094 
paint(QPainter * p,const QRect & damageRect,bool selectionOnly)1095 void RenderLayer::paint(QPainter *p, const QRect &damageRect, bool selectionOnly)
1096 {
1097     paintLayer(this, p, damageRect, selectionOnly);
1098 }
1099 
setClip(QPainter * p,const QRect & paintDirtyRect,const QRect & clipRect,bool)1100 void RenderLayer::setClip(QPainter *p, const QRect &paintDirtyRect, const QRect &clipRect, bool /*setup*/)
1101 {
1102     if (paintDirtyRect == clipRect) {
1103         return;
1104     }
1105     KHTMLView *v = m_object->canvas()->view();
1106     QRegion r = clipRect;
1107     if (p->hasClipping()) {
1108         if (!v->clipHolder()) {
1109             v->setClipHolder(new QStack<QRegion>);
1110         }
1111         v->clipHolder()->push(p->clipRegion());
1112         r &= v->clipHolder()->top();
1113     }
1114     p->setClipRegion(r);
1115 }
1116 
restoreClip(QPainter * p,const QRect & paintDirtyRect,const QRect & clipRect,bool)1117 void RenderLayer::restoreClip(QPainter *p, const QRect &paintDirtyRect, const QRect &clipRect, bool /*cleanup*/)
1118 {
1119     if (paintDirtyRect == clipRect) {
1120         return;
1121     }
1122     KHTMLView *v = m_object->document()->view();
1123     if (v->clipHolder() && !v->clipHolder()->isEmpty()) {
1124         p->setClipRegion(v->clipHolder()->pop());
1125     } else {
1126         p->setClipRegion(QRegion(), Qt::NoClip);
1127     }
1128 }
1129 
paintLayer(RenderLayer * rootLayer,QPainter * p,const QRect & paintDirtyRect,bool selectionOnly)1130 void RenderLayer::paintLayer(RenderLayer *rootLayer, QPainter *p,
1131                              const QRect &paintDirtyRect, bool selectionOnly)
1132 {
1133     assert(rootLayer != this || !m_object->canvas()->view()->clipHolder());
1134 
1135     if (!m_object->style()->opacity()) {
1136         return;
1137     }
1138 
1139     // Calculate the clip rects we should use.
1140     QRect layerBounds, damageRect, clipRectToApply;
1141     calculateRects(rootLayer, paintDirtyRect, layerBounds, damageRect, clipRectToApply);
1142     int x = layerBounds.x();
1143     int y = layerBounds.y();
1144 
1145     // Ensure our lists are up-to-date.
1146     updateZOrderLists();
1147     updateOverflowList();
1148 
1149     // Set our transparency if we need to.
1150     khtml::BufferedPainter *bPainter = nullptr;
1151     if (isTransparent()) {
1152         //### cache paintedRegion
1153         QRegion rr = paintedRegion(rootLayer) & damageRect;
1154         if (p->hasClipping()) {
1155             rr &= p->clipRegion();
1156         }
1157         bPainter = khtml::BufferedPainter::start(p, rr);
1158     }
1159     // We want to paint our layer, but only if we intersect the damage rect.
1160     bool shouldPaint = intersectsDamageRect(layerBounds, damageRect) && m_hasVisibleContent;
1161     if (shouldPaint && !selectionOnly) {
1162         // Paint our background first, before painting any child layers.
1163         if (!damageRect.isEmpty()) {
1164             // Establish the clip used to paint our background.
1165             setClip(p, paintDirtyRect, damageRect);
1166 
1167             // Paint the background.
1168             RenderObject::PaintInfo paintInfo(p, damageRect, PaintActionElementBackground);
1169             renderer()->paint(paintInfo,
1170                               x - renderer()->xPos(), y - renderer()->yPos() + renderer()->borderTopExtra());
1171 
1172             // Position our scrollbars.
1173             positionScrollbars(layerBounds);
1174 
1175             // Our scrollbar widgets paint exactly when we tell them to, so that they work properly with
1176             // z-index.  We paint after we painted the background/border, so that the scrollbars will
1177             // sit above the background/border.
1178             paintScrollbars(paintInfo);
1179 
1180             // Restore the clip.
1181             restoreClip(p, paintDirtyRect, damageRect);
1182         }
1183     }
1184 
1185     // Now walk the sorted list of children with negative z-indices.
1186     if (m_negZOrderList) {
1187         for (int i = 0; i < m_negZOrderList->count(); i++) {
1188             RenderLayer *child = m_negZOrderList->at(i);
1189             child->paintLayer(rootLayer, p, paintDirtyRect, selectionOnly);
1190         }
1191     }
1192 
1193     // Now establish the appropriate clip and paint our child RenderObjects.
1194     if (shouldPaint && !clipRectToApply.isEmpty()) {
1195         // Set up the clip used when painting our children.
1196         setClip(p, paintDirtyRect, clipRectToApply);
1197 
1198         RenderObject::PaintInfo paintInfo(p, clipRectToApply, PaintActionSelection);
1199 
1200         int tx = x - renderer()->xPos();
1201         int ty = y - renderer()->yPos() + renderer()->borderTopExtra();
1202 
1203         if (selectionOnly) {
1204             renderer()->paint(paintInfo, tx, ty);
1205         } else {
1206             paintInfo.phase = PaintActionChildBackgrounds;
1207             renderer()->paint(paintInfo, tx, ty);
1208             paintInfo.phase = PaintActionFloat;
1209             renderer()->paint(paintInfo, tx, ty);
1210             paintInfo.phase = PaintActionForeground;
1211             renderer()->paint(paintInfo, tx, ty);
1212             RenderCanvas *rc = static_cast<RenderCanvas *>(renderer()->document()->renderer());
1213             if (rc->maximalOutlineSize()) {
1214                 paintInfo.phase = PaintActionOutline;
1215                 renderer()->paint(paintInfo, tx, ty);
1216             }
1217             if (renderer()->canvas()->hasSelection()) {
1218                 paintInfo.phase = PaintActionSelection;
1219                 renderer()->paint(paintInfo, tx, ty);
1220             }
1221         }
1222 
1223         // Now restore our clip.
1224         restoreClip(p, paintDirtyRect, clipRectToApply);
1225     }
1226 
1227     // Paint any child layers that have overflow.
1228     if (m_overflowList)
1229         foreach (RenderLayer *layer, *m_overflowList) {
1230             layer->paintLayer(rootLayer, p, paintDirtyRect, selectionOnly);
1231         }
1232 
1233     // Now walk the sorted list of children with positive z-indices.
1234     if (m_posZOrderList) {
1235         for (int i = 0; i < m_posZOrderList->count(); i++) {
1236             RenderLayer *child = m_posZOrderList->at(i);
1237             child->paintLayer(rootLayer, p, paintDirtyRect, selectionOnly);
1238         }
1239     }
1240 
1241 #ifdef BOX_DEBUG
1242     {
1243         int ax = 0;
1244         int ay = 0;
1245         renderer()->absolutePosition(ax, ay);
1246         p->setPen(QPen(QColor("yellow"), 1, Qt::DotLine));
1247         p->setBrush(Qt::NoBrush);
1248         p->drawRect(ax, ay, width(), height());
1249     }
1250 #endif
1251 
1252     // End our transparency layer
1253     if (bPainter) {
1254         khtml::BufferedPainter::end(p, bPainter, m_object->style()->opacity());
1255     }
1256 
1257     if (rootLayer == this && m_object->canvas()->view()->clipHolder()) {
1258         KHTMLView *const v = m_object->canvas()->view();
1259         assert(v->clipHolder()->isEmpty());
1260         delete v->clipHolder();
1261         v->setClipHolder(nullptr);
1262     }
1263 }
1264 
nodeAtPoint(RenderObject::NodeInfo & info,int x,int y)1265 bool RenderLayer::nodeAtPoint(RenderObject::NodeInfo &info, int x, int y)
1266 {
1267     // Clear our our scrollbar variable
1268     RenderLayer::gScrollBar = nullptr;
1269 
1270     int stx = m_x;
1271     int sty = m_y;
1272 
1273     if (renderer()->isCanvas()) {
1274         static_cast<RenderCanvas *>(renderer())->view()->revertTransforms(stx, sty);
1275     }
1276 
1277     QRect damageRect(stx, sty, width(), height());
1278     RenderLayer *insideLayer = nodeAtPointForLayer(this, info, x, y, damageRect);
1279 
1280     // Now determine if the result is inside an anchor.
1281     DOM::NodeImpl *node = info.innerNode();
1282     while (node) {
1283         if (node->hasAnchor() && !info.URLElement()) {
1284             info.setURLElement(node);
1285         }
1286         node = node->parentNode();
1287     }
1288 
1289     // Next set up the correct :hover/:active state along the new chain.
1290     updateHoverActiveState(info);
1291 
1292     // Now return whether we were inside this layer (this will always be true for the root
1293     // layer).
1294     return insideLayer;
1295 }
1296 
nodeAtPointForLayer(RenderLayer * rootLayer,RenderObject::NodeInfo & info,int xMousePos,int yMousePos,const QRect & hitTestRect)1297 RenderLayer *RenderLayer::nodeAtPointForLayer(RenderLayer *rootLayer, RenderObject::NodeInfo &info,
1298         int xMousePos, int yMousePos, const QRect &hitTestRect)
1299 {
1300     // Calculate the clip rects we should use.
1301     QRect layerBounds, bgRect, fgRect;
1302     calculateRects(rootLayer, hitTestRect, layerBounds, bgRect, fgRect);
1303 
1304     // Ensure our lists are up-to-date.
1305     updateZOrderLists();
1306     updateOverflowList();
1307 
1308     // This variable tracks which layer the mouse ends up being inside.  The minute we find an insideLayer,
1309     // we are done and can return it.
1310     RenderLayer *insideLayer = nullptr;
1311 
1312     // Begin by walking our list of positive layers from highest z-index down to the lowest
1313     // z-index.
1314     if (m_posZOrderList) {
1315         uint count = m_posZOrderList->count();
1316         for (int i = count - 1; i >= 0; i--) {
1317             RenderLayer *child = m_posZOrderList->at(i);
1318             insideLayer = child->nodeAtPointForLayer(rootLayer, info, xMousePos, yMousePos, hitTestRect);
1319             if (insideLayer) {
1320                 return insideLayer;
1321             }
1322         }
1323     }
1324 
1325     // Now check our overflow objects.
1326     if (m_overflowList) {
1327         QVector<RenderLayer *>::iterator it = m_overflowList->end();
1328         while (it != m_overflowList->begin()) {
1329             --it;
1330             insideLayer = (*it)->nodeAtPointForLayer(rootLayer, info,  xMousePos, yMousePos, hitTestRect);
1331             if (insideLayer) {
1332                 return insideLayer;
1333             }
1334         }
1335     }
1336 
1337     // Next we want to see if the mouse pos is inside the child RenderObjects of the layer.
1338     if (containsPoint(xMousePos, yMousePos, fgRect) &&
1339             renderer()->nodeAtPoint(info, xMousePos, yMousePos,
1340                                     layerBounds.x() - renderer()->xPos(),
1341                                     layerBounds.y() - renderer()->yPos() + m_object->borderTopExtra(),
1342                                     HitTestChildrenOnly)) {
1343         if (info.innerNode() != m_object->element()) {
1344             return this;
1345         }
1346     }
1347 
1348     // Now check our negative z-index children.
1349     if (m_negZOrderList) {
1350         uint count = m_negZOrderList->count();
1351         for (int i = count - 1; i >= 0; i--) {
1352             RenderLayer *child = m_negZOrderList->at(i);
1353             insideLayer = child->nodeAtPointForLayer(rootLayer, info, xMousePos, yMousePos, hitTestRect);
1354             if (insideLayer) {
1355                 return insideLayer;
1356             }
1357         }
1358     }
1359 
1360     // Next we want to see if the mouse pos is inside this layer but not any of its children.
1361     if (containsPoint(xMousePos, yMousePos, bgRect) &&
1362             renderer()->nodeAtPoint(info, xMousePos, yMousePos,
1363                                     layerBounds.x() - renderer()->xPos(),
1364                                     layerBounds.y() - renderer()->yPos() + m_object->borderTopExtra(),
1365                                     HitTestSelfOnly)) {
1366         return this;
1367     }
1368 
1369     // No luck.
1370     return nullptr;
1371 }
1372 
calculateClipRects(const RenderLayer * rootLayer,QRect & overflowClipRect,QRect & posClipRect,QRect & fixedClipRect)1373 void RenderLayer::calculateClipRects(const RenderLayer *rootLayer, QRect &overflowClipRect,
1374                                      QRect &posClipRect, QRect &fixedClipRect)
1375 {
1376     if (parent()) {
1377         parent()->calculateClipRects(rootLayer, overflowClipRect, posClipRect, fixedClipRect);
1378     }
1379 
1380     switch (m_object->style()->position()) {
1381     // A fixed object is essentially the root of its containing block hierarchy, so when
1382     // we encounter such an object, we reset our clip rects to the fixedClipRect.
1383     case PFIXED:
1384         posClipRect = fixedClipRect;
1385         overflowClipRect = fixedClipRect;
1386         break;
1387     case PABSOLUTE:
1388         overflowClipRect = posClipRect;
1389         break;
1390     case PRELATIVE:
1391         posClipRect = overflowClipRect;
1392         break;
1393     default:
1394         break;
1395     }
1396 
1397     // Update the clip rects that will be passed to child layers.
1398     if (m_object->hasOverflowClip() || m_object->hasClip()) {
1399         // This layer establishes a clip of some kind.
1400         int x = 0;
1401         int y = 0;
1402         convertToLayerCoords(rootLayer, x, y);
1403 
1404         if (m_object->hasOverflowClip()) {
1405             QRect newOverflowClip = m_object->overflowClipRect(x, y);
1406             overflowClipRect  = newOverflowClip.intersected(overflowClipRect);
1407             if (m_object->isPositioned() || m_object->isRelPositioned()) {
1408                 posClipRect = newOverflowClip.intersected(posClipRect);
1409             }
1410         }
1411         if (m_object->hasClip()) {
1412             QRect newPosClip = m_object->clipRect(x, y);
1413             posClipRect = posClipRect.intersected(newPosClip);
1414             overflowClipRect = overflowClipRect.intersected(newPosClip);
1415             fixedClipRect = fixedClipRect.intersected(newPosClip);
1416         }
1417     }
1418 }
1419 
calculateRects(const RenderLayer * rootLayer,const QRect & paintDirtyRect,QRect & layerBounds,QRect & backgroundRect,QRect & foregroundRect)1420 void RenderLayer::calculateRects(const RenderLayer *rootLayer, const QRect &paintDirtyRect, QRect &layerBounds,
1421                                  QRect &backgroundRect, QRect &foregroundRect)
1422 {
1423     QRect overflowClipRect = paintDirtyRect;
1424     QRect posClipRect = paintDirtyRect;
1425     QRect fixedClipRect = paintDirtyRect;
1426     if (parent()) {
1427         parent()->calculateClipRects(rootLayer, overflowClipRect, posClipRect, fixedClipRect);
1428     }
1429 
1430     int x = 0;
1431     int y = 0;
1432     convertToLayerCoords(rootLayer, x, y);
1433     layerBounds = QRect(x, y, width(), height());
1434 
1435     backgroundRect = m_object->style()->position() == PFIXED ? fixedClipRect :
1436                      (m_object->isPositioned() ? posClipRect : overflowClipRect);
1437     foregroundRect = backgroundRect;
1438 
1439     // Update the clip rects that will be passed to child layers.
1440     if (m_object->hasOverflowClip() || m_object->hasClip()) {
1441         // This layer establishes a clip of some kind.
1442         if (m_object->hasOverflowClip()) {
1443             foregroundRect = foregroundRect.intersected(m_object->overflowClipRect(x, y));
1444         }
1445 
1446         if (m_object->hasClip()) {
1447             // Clip applies to *us* as well, so go ahead and update the damageRect.
1448             QRect newPosClip = m_object->clipRect(x, y);
1449             backgroundRect = backgroundRect.intersected(newPosClip);
1450             foregroundRect = foregroundRect.intersected(newPosClip);
1451         }
1452 
1453         // If we establish a clip at all, then go ahead and make sure our background
1454         // rect is intersected with our layer's bounds.
1455         backgroundRect = backgroundRect.intersected(layerBounds);
1456     }
1457 }
1458 
intersectsDamageRect(const QRect & layerBounds,const QRect & damageRect) const1459 bool RenderLayer::intersectsDamageRect(const QRect &layerBounds, const QRect &damageRect) const
1460 {
1461     return (renderer()->isCanvas() || renderer()->isRoot() || renderer()->isBody() ||
1462             (renderer()->hasOverhangingFloats() && !renderer()->hasOverflowClip()) ||
1463             (renderer()->isInline() && !renderer()->isReplaced()) ||
1464             layerBounds.intersects(damageRect));
1465 }
1466 
containsPoint(int x,int y,const QRect & damageRect) const1467 bool RenderLayer::containsPoint(int x, int y, const QRect &damageRect) const
1468 {
1469     return (renderer()->isCanvas() || renderer()->isRoot() || renderer()->isInlineFlow() ||
1470             damageRect.contains(x, y));
1471 }
1472 
1473 // This code has been written to anticipate the addition of CSS3-::outside and ::inside generated
1474 // content (and perhaps XBL).  That's why it uses the render tree and not the DOM tree.
hoverAncestor(RenderObject * obj)1475 static RenderObject *hoverAncestor(RenderObject *obj)
1476 {
1477     return (!obj->isInline() && obj->continuation()) ? obj->continuation() : obj->parent();
1478 }
1479 
commonAncestor(RenderObject * obj1,RenderObject * obj2)1480 static RenderObject *commonAncestor(RenderObject *obj1, RenderObject *obj2)
1481 {
1482     if (!obj1 || !obj2) {
1483         return nullptr;
1484     }
1485 
1486     for (RenderObject *currObj1 = obj1; currObj1; currObj1 = hoverAncestor(currObj1))
1487         for (RenderObject *currObj2 = obj2; currObj2; currObj2 = hoverAncestor(currObj2))
1488             if (currObj1 == currObj2) {
1489                 return currObj1;
1490             }
1491 
1492     return nullptr;
1493 }
1494 
updateHoverActiveState(RenderObject::NodeInfo & info)1495 void RenderLayer::updateHoverActiveState(RenderObject::NodeInfo &info)
1496 {
1497     // We don't update :hover/:active state when the info is marked as readonly.
1498     if (info.readonly()) {
1499         return;
1500     }
1501 
1502     DOM::NodeImpl *e = m_object->element();
1503     DOM::DocumentImpl *doc = e ? e->document() : nullptr;
1504     if (!doc) {
1505         return;
1506     }
1507 
1508     // Check to see if the hovered node has changed.  If not, then we don't need to
1509     // do anything.
1510     DOM::NodeImpl *oldHoverNode = doc->hoverNode();
1511     DOM::NodeImpl *newHoverNode = info.innerNode();
1512 
1513     if (oldHoverNode == newHoverNode && (!oldHoverNode || oldHoverNode->active() == info.active())) {
1514         return;
1515     }
1516 
1517     // Update our current hover node.
1518     doc->setHoverNode(newHoverNode);
1519     if (info.active()) {
1520         doc->setActiveNode(newHoverNode);
1521     } else {
1522         doc->setActiveNode(nullptr);
1523     }
1524 
1525     // We have two different objects.  Fetch their renderers.
1526     RenderObject *oldHoverObj = oldHoverNode ? oldHoverNode->renderer() : nullptr;
1527     RenderObject *newHoverObj = newHoverNode ? newHoverNode->renderer() : nullptr;
1528 
1529     // Locate the common ancestor render object for the two renderers.
1530     RenderObject *ancestor = commonAncestor(oldHoverObj, newHoverObj);
1531 
1532     // The old hover path only needs to be cleared up to (and not including) the common ancestor;
1533     for (RenderObject *curr = oldHoverObj; curr && curr != ancestor; curr = hoverAncestor(curr)) {
1534         curr->setMouseInside(false);
1535         if (curr->element()) {
1536             curr->element()->setActive(false);
1537             curr->element()->setHovered(false);
1538         }
1539     }
1540 
1541     // Now set the hover state for our new object up to the root.
1542     for (RenderObject *curr = newHoverObj; curr; curr = hoverAncestor(curr)) {
1543         curr->setMouseInside(true);
1544         if (curr->element()) {
1545             curr->element()->setActive(info.active());
1546             curr->element()->setHovered(true);
1547         }
1548     }
1549 }
1550 
1551 // Sort the buffer from lowest z-index to highest.  The common scenario will have
1552 // most z-indices equal, so we optimize for that case (i.e., the list will be mostly
1553 // sorted already).
sortByZOrder(QVector<RenderLayer * > * buffer,QVector<RenderLayer * > * mergeBuffer,uint start,uint end)1554 static void sortByZOrder(QVector<RenderLayer *> *buffer,
1555                          QVector<RenderLayer *> *mergeBuffer,
1556                          uint start, uint end)
1557 {
1558     if (start >= end) {
1559         return;    // Sanity check.
1560     }
1561 
1562     if (end - start <= 6) {
1563         // Apply a bubble sort for smaller lists.
1564         for (uint i = end - 1; i > start; i--) {
1565             bool sorted = true;
1566             for (uint j = start; j < i; j++) {
1567                 RenderLayer *elt = buffer->at(j);
1568                 RenderLayer *elt2 = buffer->at(j + 1);
1569                 if (elt->zIndex() > elt2->zIndex()) {
1570                     sorted = false;
1571                     buffer->replace(j, elt2);
1572                     buffer->replace(j + 1, elt);
1573                 }
1574             }
1575             if (sorted) {
1576                 return;
1577             }
1578         }
1579     } else {
1580         // Peform a merge sort for larger lists.
1581         uint mid = (start + end) / 2;
1582         sortByZOrder(buffer, mergeBuffer, start, mid);
1583         sortByZOrder(buffer, mergeBuffer, mid, end);
1584 
1585         RenderLayer *elt = buffer->at(mid - 1);
1586         RenderLayer *elt2 = buffer->at(mid);
1587 
1588         // Handle the fast common case (of equal z-indices).  The list may already
1589         // be completely sorted.
1590         if (elt->zIndex() <= elt2->zIndex()) {
1591             return;
1592         }
1593 
1594         // We have to merge sort.
1595         uint i1 = start;
1596         uint i2 = mid;
1597 
1598         elt = buffer->at(i1);
1599         elt2 = buffer->at(i2);
1600 
1601         while (i1 < mid || i2 < end) {
1602             if (i1 < mid && (i2 == end || elt->zIndex() <= elt2->zIndex())) {
1603                 mergeBuffer->append(elt);
1604                 i1++;
1605                 if (i1 < mid) {
1606                     elt = buffer->at(i1);
1607                 }
1608             } else {
1609                 mergeBuffer->append(elt2);
1610                 i2++;
1611                 if (i2 < end) {
1612                     elt2 = buffer->at(i2);
1613                 }
1614             }
1615         }
1616 
1617         for (uint i = start; i < end; i++) {
1618             buffer->replace(i, mergeBuffer->at(i - start));
1619         }
1620 
1621         mergeBuffer->clear();
1622     }
1623 }
1624 
dirtyZOrderLists()1625 void RenderLayer::dirtyZOrderLists()
1626 {
1627     if (m_posZOrderList) {
1628         m_posZOrderList->clear();
1629     }
1630     if (m_negZOrderList) {
1631         m_negZOrderList->clear();
1632     }
1633     m_zOrderListsDirty = true;
1634 }
1635 
dirtyOverflowList()1636 void RenderLayer::dirtyOverflowList()
1637 {
1638     if (m_overflowList) {
1639         m_overflowList->clear();
1640     }
1641     m_overflowListDirty = true;
1642 }
1643 
updateZOrderLists()1644 void RenderLayer::updateZOrderLists()
1645 {
1646     if (!isStackingContext() || !m_zOrderListsDirty) {
1647         return;
1648     }
1649 
1650     for (RenderLayer *child = firstChild(); child; child = child->nextSibling()) {
1651         child->collectLayers(m_posZOrderList, m_negZOrderList);
1652     }
1653 
1654     // Sort the two lists.
1655     if (m_posZOrderList) {
1656         QVector<RenderLayer *> mergeBuffer;
1657         sortByZOrder(m_posZOrderList, &mergeBuffer, 0, m_posZOrderList->count());
1658     }
1659     if (m_negZOrderList) {
1660         QVector<RenderLayer *> mergeBuffer;
1661         sortByZOrder(m_negZOrderList, &mergeBuffer, 0, m_negZOrderList->count());
1662     }
1663 
1664     m_zOrderListsDirty = false;
1665 }
1666 
updateOverflowList()1667 void RenderLayer::updateOverflowList()
1668 {
1669     if (!m_overflowListDirty) {
1670         return;
1671     }
1672 
1673     for (RenderLayer *child = firstChild(); child; child = child->nextSibling()) {
1674         if (child->isOverflowOnly()) {
1675             if (!m_overflowList) {
1676                 m_overflowList = new QVector<RenderLayer *>;
1677             }
1678             m_overflowList->append(child);
1679         }
1680     }
1681 
1682     m_overflowListDirty = false;
1683 }
1684 
collectLayers(QVector<RenderLayer * > * & posBuffer,QVector<RenderLayer * > * & negBuffer)1685 void RenderLayer::collectLayers(QVector<RenderLayer *> *&posBuffer, QVector<RenderLayer *> *&negBuffer)
1686 {
1687     updateVisibilityStatus();
1688 
1689     // Overflow layers are just painted by their enclosing layers, so they don't get put in zorder lists.
1690     if ((m_hasVisibleContent || (m_hasVisibleDescendant && isStackingContext())) && !isOverflowOnly()) {
1691         // Determine which buffer the child should be in.
1692         QVector<RenderLayer *> *&buffer = (zIndex() >= 0) ? posBuffer : negBuffer;
1693 
1694         // Create the buffer if it doesn't exist yet.
1695         if (!buffer) {
1696             buffer = new QVector<RenderLayer *>();
1697         }
1698 
1699         // Append ourselves at the end of the appropriate buffer.
1700         buffer->append(this);
1701     }
1702 
1703     // Recur into our children to collect more layers, but only if we don't establish
1704     // a stacking context.
1705     if (m_hasVisibleDescendant && !isStackingContext()) {
1706         for (RenderLayer *child = firstChild(); child; child = child->nextSibling()) {
1707             child->collectLayers(posBuffer, negBuffer);
1708         }
1709     }
1710 }
1711 
1712 #ifdef ENABLE_DUMP
operator <<(QTextStream & ts,const QRect & r)1713 static QTextStream &operator<<(QTextStream &ts, const QRect &r)
1714 {
1715     return ts << "at (" << r.x() << "," << r.y() << ") size " << r.width() << "x" << r.height();
1716 }
1717 
write(QTextStream & ts,RenderObject & o,const QString & indent)1718 static void write(QTextStream &ts, RenderObject &o, const QString &indent)
1719 {
1720     o.dump(ts, indent);
1721 
1722     for (RenderObject *child = o.firstChild(); child; child = child->nextSibling()) {
1723         if (child->layer()) {
1724             continue;
1725         }
1726         write(ts, *child, indent + "   ");
1727     }
1728 }
1729 
write(QTextStream & ts,const RenderLayer & l,const QRect & layerBounds,const QRect & backgroundClipRect,const QRect & clipRect,int layerType=0,const QString & indent=QString ())1730 static void write(QTextStream &ts, const RenderLayer &l,
1731                   const QRect &layerBounds, const QRect &backgroundClipRect, const QRect &clipRect,
1732                   int layerType = 0, const QString &indent = QString())
1733 
1734 {
1735     ts << indent << "layer";
1736 
1737     ts << " at (" << l.xPos() << "," << l.yPos() << ") size " << l.width() << "x" << l.height();
1738 
1739     if (layerBounds != layerBounds.intersected(backgroundClipRect)) {
1740         ts << " backgroundClip " << backgroundClipRect;
1741     }
1742     if (layerBounds != layerBounds.intersected(clipRect)) {
1743         ts << " clip " << clipRect;
1744     }
1745 
1746     if (layerType == -1) {
1747         ts << " layerType: background only";
1748     } else if (layerType == 1) {
1749         ts << " layerType: foreground only";
1750     }
1751 
1752     ts << "\n";
1753 
1754     if (layerType != -1) {
1755         write(ts, *l.renderer(), indent + "   ");
1756     }
1757 
1758     ts << "\n";
1759 }
1760 
writeLayers(QTextStream & ts,const RenderLayer * rootLayer,RenderLayer * l,const QRect & paintDirtyRect,const QString & indent)1761 static void writeLayers(QTextStream &ts, const RenderLayer *rootLayer, RenderLayer *l,
1762                         const QRect &paintDirtyRect, const QString &indent)
1763 {
1764     // Calculate the clip rects we should use.
1765     QRect layerBounds, damageRect, clipRectToApply;
1766     l->calculateRects(rootLayer, paintDirtyRect, layerBounds, damageRect, clipRectToApply);
1767 
1768     // Ensure our lists are up-to-date.
1769     l->updateZOrderLists();
1770     l->updateOverflowList();
1771 
1772     bool shouldPaint = l->intersectsDamageRect(layerBounds, damageRect);
1773     QVector<RenderLayer *> *negList = l->negZOrderList();
1774     QVector<RenderLayer *> *ovfList = l->overflowList();
1775     if (shouldPaint && negList && negList->count() > 0) {
1776         write(ts, *l, layerBounds, damageRect, clipRectToApply, -1, indent);
1777     }
1778 
1779     if (negList) {
1780         for (int i = 0; i != negList->count(); ++i) {
1781             writeLayers(ts, rootLayer, negList->at(i), paintDirtyRect, indent);
1782         }
1783     }
1784 
1785     if (shouldPaint) {
1786         write(ts, *l, layerBounds, damageRect, clipRectToApply, negList && negList->count() > 0, indent);
1787     }
1788 
1789     if (ovfList) {
1790         for (QVector<RenderLayer *>::iterator it = ovfList->begin(); it != ovfList->end(); ++it) {
1791             writeLayers(ts, rootLayer, *it, paintDirtyRect, indent);
1792         }
1793     }
1794 
1795     QVector<RenderLayer *> *posList = l->posZOrderList();
1796     if (posList) {
1797         for (int i = 0; i != posList->count(); ++i) {
1798             writeLayers(ts, rootLayer, posList->at(i), paintDirtyRect, indent);
1799         }
1800     }
1801 }
1802 
dump(QTextStream & ts,const QString & ind)1803 void RenderLayer::dump(QTextStream &ts, const QString &ind)
1804 {
1805     assert(renderer()->isCanvas());
1806 
1807     writeLayers(ts, this, this, QRect(xPos(), yPos(), width(), height()), ind);
1808 }
1809 
1810 #endif
1811 
shouldBeOverflowOnly() const1812 bool RenderLayer::shouldBeOverflowOnly() const
1813 {
1814     return renderer()->style() && renderer()->hasOverflowClip() &&
1815            !renderer()->isPositioned() && !renderer()->isRelPositioned() && !isTransparent();
1816 }
1817 
styleChanged()1818 void RenderLayer::styleChanged()
1819 {
1820     RenderLayer *parentSC = stackingContext();
1821 
1822     // If we stopped being a stacking context, make sure to clear our
1823     // child lists so we don't end up with dangling references when a kid
1824     // is removed (as it wouldn't know to remove from us)
1825     bool nowStackingContext = isStackingContext();
1826     if (!nowStackingContext && (m_posZOrderList || m_negZOrderList)) {
1827         delete m_posZOrderList;
1828         m_posZOrderList = nullptr;
1829         delete m_negZOrderList;
1830         m_negZOrderList = nullptr;
1831     }
1832 
1833     // If we stopped or started being a stacking context, dirty the parent, as
1834     // who is responsible for some of the layers may change
1835     if (nowStackingContext != m_wasStackingContext && parentSC) {
1836         parentSC->dirtyZOrderLists();
1837     }
1838 
1839     m_wasStackingContext = nowStackingContext;
1840 
1841     bool isOverflowOnly = shouldBeOverflowOnly();
1842     if (isOverflowOnly != m_isOverflowOnly) {
1843         m_isOverflowOnly = isOverflowOnly;
1844         RenderLayer *p = parent();
1845         if (p) {
1846             p->dirtyOverflowList();
1847         }
1848         if (parentSC) {
1849             parentSC->dirtyZOrderLists();
1850         }
1851     }
1852 
1853     if (m_object->hasOverflowClip() &&
1854             m_object->style()->overflowX() == OMARQUEE && m_object->style()->marqueeBehavior() != MNONE) {
1855         if (!m_marquee) {
1856             m_marquee = new Marquee(this);
1857         }
1858         m_marquee->updateMarqueeStyle();
1859     } else if (m_marquee) {
1860         delete m_marquee;
1861         m_marquee = nullptr;
1862     }
1863 }
1864 
suspendMarquees()1865 void RenderLayer::suspendMarquees()
1866 {
1867     if (m_marquee) {
1868         m_marquee->suspend();
1869     }
1870 
1871     for (RenderLayer *curr = firstChild(); curr; curr = curr->nextSibling()) {
1872         curr->suspendMarquees();
1873     }
1874 }
1875 
1876 // --------------------------------------------------------------------------
1877 // Marquee implementation
1878 
Marquee(RenderLayer * l)1879 Marquee::Marquee(RenderLayer *l)
1880     : 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),
1881       m_suspended(false), m_stopped(false), m_whiteSpace(NORMAL), m_direction(MAUTO)
1882 {
1883 }
1884 
marqueeSpeed() const1885 int Marquee::marqueeSpeed() const
1886 {
1887     int result = m_layer->renderer()->style()->marqueeSpeed();
1888     DOM::NodeImpl *elt = m_layer->renderer()->element();
1889     if (elt && elt->id() == ID_MARQUEE) {
1890         HTMLMarqueeElementImpl *marqueeElt = static_cast<HTMLMarqueeElementImpl *>(elt);
1891         result = qMax(result, marqueeElt->minimumDelay());
1892     }
1893     return result;
1894 }
1895 
direction() const1896 EMarqueeDirection Marquee::direction() const
1897 {
1898     // FIXME: Support the CSS3 "auto" value for determining the direction of the marquee.
1899     // For now just map MAUTO to MBACKWARD
1900     EMarqueeDirection result = m_layer->renderer()->style()->marqueeDirection();
1901     EDirection dir =  m_layer->renderer()->style()->direction();
1902     if (result == MAUTO) {
1903         result = MBACKWARD;
1904     }
1905     if (result == MFORWARD) {
1906         result = (dir == LTR) ? MRIGHT : MLEFT;
1907     }
1908     if (result == MBACKWARD) {
1909         result = (dir == LTR) ? MLEFT : MRIGHT;
1910     }
1911 
1912     // Now we have the real direction.  Next we check to see if the increment is negative.
1913     // If so, then we reverse the direction.
1914     Length increment = m_layer->renderer()->style()->marqueeIncrement();
1915     if (increment.isNegative()) {
1916         result = static_cast<EMarqueeDirection>(-result);
1917     }
1918 
1919     return result;
1920 }
1921 
isHorizontal() const1922 bool Marquee::isHorizontal() const
1923 {
1924     return direction() == MLEFT || direction() == MRIGHT;
1925 }
1926 
isUnfurlMarquee() const1927 bool Marquee::isUnfurlMarquee() const
1928 {
1929     EMarqueeBehavior behavior = m_layer->renderer()->style()->marqueeBehavior();
1930     return (behavior == MUNFURL);
1931 }
1932 
computePosition(EMarqueeDirection dir,bool stopAtContentEdge)1933 int Marquee::computePosition(EMarqueeDirection dir, bool stopAtContentEdge)
1934 {
1935     RenderObject *o = m_layer->renderer();
1936     RenderStyle *s = o->style();
1937     if (isHorizontal()) {
1938         bool ltr = s->direction() == LTR;
1939         int clientWidth = o->clientWidth();
1940         int contentWidth = ltr ? o->rightmostPosition(true, false) : o->leftmostPosition(true, false);
1941         if (ltr) {
1942             contentWidth += (o->paddingRight() - o->borderLeft());
1943         } else {
1944             contentWidth = o->width() - contentWidth;
1945             contentWidth += (o->paddingLeft() - o->borderRight());
1946         }
1947         if (dir == MRIGHT) {
1948             if (stopAtContentEdge) {
1949                 return qMax(0, ltr ? (contentWidth - clientWidth) : (clientWidth - contentWidth));
1950             } else {
1951                 return ltr ? contentWidth : clientWidth;
1952             }
1953         } else {
1954             if (stopAtContentEdge) {
1955                 return qMin(0, ltr ? (contentWidth - clientWidth) : (clientWidth - contentWidth));
1956             } else {
1957                 return ltr ? -clientWidth : -contentWidth;
1958             }
1959         }
1960     } else {
1961         int contentHeight = m_layer->renderer()->lowestPosition(true, false) -
1962                             m_layer->renderer()->borderTop() + m_layer->renderer()->paddingBottom();
1963         int clientHeight = m_layer->renderer()->clientHeight();
1964         if (dir == MUP) {
1965             if (stopAtContentEdge) {
1966                 return qMin(contentHeight - clientHeight, 0);
1967             } else {
1968                 return -clientHeight;
1969             }
1970         } else {
1971             if (stopAtContentEdge) {
1972                 return qMax(contentHeight - clientHeight, 0);
1973             } else {
1974                 return contentHeight;
1975             }
1976         }
1977     }
1978 }
1979 
start()1980 void Marquee::start()
1981 {
1982     if (m_timerId || m_layer->renderer()->style()->marqueeIncrement().isZero()) {
1983         return;
1984     }
1985 
1986     if (!m_suspended && !m_stopped) {
1987         if (isUnfurlMarquee()) {
1988             bool forward = direction() == MDOWN || direction() == MRIGHT;
1989             bool isReversed = (forward && m_currentLoop % 2) || (!forward && !(m_currentLoop % 2));
1990             m_unfurlPos = isReversed ? m_end : m_start;
1991             m_layer->renderer()->setChildNeedsLayout(true);
1992         } else {
1993             if (isHorizontal()) {
1994                 m_layer->scrollToOffset(m_start, 0, false, false, false);
1995             } else {
1996                 m_layer->scrollToOffset(0, m_start, false, false, false);
1997             }
1998         }
1999     } else {
2000         m_suspended = false;
2001     }
2002 
2003     m_stopped = false;
2004     m_timerId = startTimer(speed());
2005 }
2006 
suspend()2007 void Marquee::suspend()
2008 {
2009     if (m_timerId) {
2010         killTimer(m_timerId);
2011         m_timerId = 0;
2012     }
2013 
2014     m_suspended = true;
2015 }
2016 
stop()2017 void Marquee::stop()
2018 {
2019     if (m_timerId) {
2020         killTimer(m_timerId);
2021         m_timerId = 0;
2022     }
2023 
2024     m_stopped = true;
2025 }
2026 
updateMarqueePosition()2027 void Marquee::updateMarqueePosition()
2028 {
2029     bool activate = (m_totalLoops <= 0 || m_currentLoop < m_totalLoops);
2030     if (activate) {
2031         if (isUnfurlMarquee()) {
2032             if (m_unfurlPos < m_start) {
2033                 m_unfurlPos = m_start;
2034                 m_layer->renderer()->setChildNeedsLayout(true);
2035             } else if (m_unfurlPos > m_end) {
2036                 m_unfurlPos = m_end;
2037                 m_layer->renderer()->setChildNeedsLayout(true);
2038             }
2039         } else {
2040             EMarqueeBehavior behavior = m_layer->renderer()->style()->marqueeBehavior();
2041             m_start = computePosition(direction(), behavior == MALTERNATE);
2042             m_end = computePosition(reverseDirection(), behavior == MALTERNATE || behavior == MSLIDE);
2043         }
2044         if (!m_stopped) {
2045             start();
2046         }
2047     }
2048 }
2049 
updateMarqueeStyle()2050 void Marquee::updateMarqueeStyle()
2051 {
2052     RenderStyle *s = m_layer->renderer()->style();
2053 
2054     if (m_direction != s->marqueeDirection() || (m_totalLoops != s->marqueeLoopCount() && m_currentLoop >= m_totalLoops)) {
2055         m_currentLoop = 0;    // When direction changes or our loopCount is a smaller number than our current loop, reset our loop.
2056     }
2057 
2058     m_totalLoops = s->marqueeLoopCount();
2059     m_direction = s->marqueeDirection();
2060     m_whiteSpace = s->whiteSpace();
2061 
2062     if (m_layer->renderer()->isHTMLMarquee()) {
2063         // Hack for WinIE.  In WinIE, a value of 0 or lower for the loop count for SLIDE means to only do
2064         // one loop.
2065         if (m_totalLoops <= 0 && (s->marqueeBehavior() == MSLIDE || s->marqueeBehavior() == MUNFURL)) {
2066             m_totalLoops = 1;
2067         }
2068 
2069         // Hack alert: Set the white-space value to nowrap for horizontal marquees with inline children, thus ensuring
2070         // all the text ends up on one line by default.  Limit this hack to the <marquee> element to emulate
2071         // WinIE's behavior.  Someone using CSS3 can use white-space: nowrap on their own to get this effect.
2072         // Second hack alert: Set the text-align back to auto.  WinIE completely ignores text-align on the
2073         // marquee element.
2074         // FIXME: Bring these up with the CSS WG.
2075         if (isHorizontal() && m_layer->renderer()->childrenInline()) {
2076             s->setWhiteSpace(NOWRAP);
2077             s->setTextAlign(TAAUTO);
2078         }
2079     }
2080 
2081     if (speed() != marqueeSpeed()) {
2082         m_speed = marqueeSpeed();
2083         if (m_timerId) {
2084             killTimer(m_timerId);
2085             m_timerId = startTimer(speed());
2086         }
2087     }
2088 
2089     // Check the loop count to see if we should now stop.
2090     bool activate = (m_totalLoops <= 0 || m_currentLoop < m_totalLoops);
2091     if (activate && !m_timerId) {
2092         m_layer->renderer()->setNeedsLayout(true);
2093     } else if (!activate && m_timerId) {
2094         // Destroy the timer.
2095         killTimer(m_timerId);
2096         m_timerId = 0;
2097     }
2098 }
2099 
timerEvent(QTimerEvent *)2100 void Marquee::timerEvent(QTimerEvent * /*evt*/)
2101 {
2102     if (m_layer->renderer()->needsLayout()) {
2103         return;
2104     }
2105 
2106     if (m_reset) {
2107         m_reset = false;
2108         if (isHorizontal()) {
2109             m_layer->scrollToXOffset(m_start);
2110         } else {
2111             m_layer->scrollToYOffset(m_start);
2112         }
2113         return;
2114     }
2115 
2116     RenderStyle *s = m_layer->renderer()->style();
2117 
2118     int endPoint = m_end;
2119     int range = m_end - m_start;
2120     int newPos;
2121     if (range == 0) {
2122         newPos = m_end;
2123     } else {
2124         bool addIncrement = direction() == MUP || direction() == MLEFT;
2125         bool isReversed = s->marqueeBehavior() == MALTERNATE && m_currentLoop % 2;
2126         if (isUnfurlMarquee()) {
2127             isReversed = (!addIncrement && m_currentLoop % 2) || (addIncrement && !(m_currentLoop % 2));
2128             addIncrement = !isReversed;
2129         }
2130         if (isReversed) {
2131             // We're going in the reverse direction.
2132             endPoint = m_start;
2133             range = -range;
2134             if (!isUnfurlMarquee()) {
2135                 addIncrement = !addIncrement;
2136             }
2137         }
2138         bool positive = range > 0;
2139         int clientSize = isUnfurlMarquee() ? abs(range) :
2140                          (isHorizontal() ? m_layer->renderer()->clientWidth() : m_layer->renderer()->clientHeight());
2141         int increment = qMax(1, abs(m_layer->renderer()->style()->marqueeIncrement().width(clientSize)));
2142         int currentPos = isUnfurlMarquee() ? m_unfurlPos :
2143                          (isHorizontal() ? m_layer->scrollXOffset() : m_layer->scrollYOffset());
2144         newPos =  currentPos + (addIncrement ? increment : -increment);
2145         if (positive) {
2146             newPos = qMin(newPos, endPoint);
2147         } else {
2148             newPos = qMax(newPos, endPoint);
2149         }
2150     }
2151 
2152     if (newPos == endPoint) {
2153         m_currentLoop++;
2154         if (m_totalLoops > 0 && m_currentLoop >= m_totalLoops) {
2155             killTimer(m_timerId);
2156             m_timerId = 0;
2157         } else if (s->marqueeBehavior() != MALTERNATE && s->marqueeBehavior() != MUNFURL) {
2158             m_reset = true;
2159         }
2160     }
2161 
2162     if (isUnfurlMarquee()) {
2163         m_unfurlPos = newPos;
2164         m_layer->renderer()->setChildNeedsLayout(true);
2165     } else {
2166         if (isHorizontal()) {
2167             m_layer->scrollToXOffset(newPos);
2168         } else {
2169             m_layer->scrollToYOffset(newPos);
2170         }
2171     }
2172 }
2173 
2174