File indexing completed on 2024-04-28 15:24:05
0001 /* 0002 * Copyright (C) 2003 Apple Computer, Inc. 0003 * (C) 2006 Germain Garand <germain@ebooksfrance.org> 0004 * (C) 2006 Allan Sandfeld Jense <kde@carewolf.com> 0005 * 0006 * Portions are Copyright (C) 1998 Netscape Communications Corporation. 0007 * 0008 * Other contributors: 0009 * Robert O'Callahan <roc+@cs.cmu.edu> 0010 * David Baron <dbaron@fas.harvard.edu> 0011 * Christian Biesinger <cbiesinger@web.de> 0012 * Randall Jesup <rjesup@wgate.com> 0013 * Roland Mainz <roland.mainz@informatik.med.uni-giessen.de> 0014 * Josh Soref <timeless@mac.com> 0015 * Boris Zbarsky <bzbarsky@mit.edu> 0016 * 0017 * This library is free software; you can redistribute it and/or 0018 * modify it under the terms of the GNU Lesser General Public 0019 * License as published by the Free Software Foundation; either 0020 * version 2.1 of the License, or (at your option) any later version. 0021 * 0022 * This library is distributed in the hope that it will be useful, 0023 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0024 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0025 * Lesser General Public License for more details. 0026 * 0027 * You should have received a copy of the GNU Lesser General Public 0028 * License along with this library; if not, write to the Free Software 0029 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 0030 * 0031 * Alternatively, the contents of this file may be used under the terms 0032 * of either the Mozilla Public License Version 1.1, found at 0033 * http://www.mozilla.org/MPL/ (the "MPL") or the GNU General Public 0034 * License Version 2.0, found at http://www.fsf.org/copyleft/gpl.html 0035 * (the "GPL"), in which case the provisions of the MPL or the GPL are 0036 * applicable instead of those above. If you wish to allow use of your 0037 * version of this file only under the terms of one of those two 0038 * licenses (the MPL or the GPL) and not to allow others to use your 0039 * version of this file under the LGPL, indicate your decision by 0040 * deletingthe provisions above and replace them with the notice and 0041 * other provisions required by the MPL or the GPL, as the case may be. 0042 * If you do not delete the provisions above, a recipient may use your 0043 * version of this file under any of the LGPL, the MPL or the GPL. 0044 */ 0045 0046 //#define BOX_DEBUG 0047 0048 #include "render_layer.h" 0049 #include "khtmlview.h" 0050 #include "render_canvas.h" 0051 #include "render_arena.h" 0052 #include "render_replaced.h" 0053 #include "render_form.h" 0054 #include "xml/dom_docimpl.h" 0055 #include "xml/dom2_eventsimpl.h" 0056 #include "misc/paintbuffer.h" 0057 #include "html/html_blockimpl.h" 0058 #include "xml/dom_restyler.h" 0059 0060 #include <QStyle> 0061 #include <QStack> 0062 0063 using namespace DOM; 0064 using namespace khtml; 0065 0066 ScrollBarWidget *RenderLayer::gScrollBar = nullptr; 0067 0068 #ifndef NDEBUG 0069 static bool inRenderLayerDetach; 0070 #endif 0071 0072 void 0073 RenderScrollMediator::slotValueChanged() 0074 { 0075 if (m_layer->renderer()->canvas()->isPerformingLayout()) { 0076 if (!m_waitingForUpdate) { 0077 QTimer::singleShot(0, this, SLOT(slotValueChanged())); 0078 } 0079 m_waitingForUpdate = true; 0080 } else { 0081 m_waitingForUpdate = false; 0082 m_layer->updateScrollPositionFromScrollbars(); 0083 } 0084 } 0085 0086 RenderLayer::RenderLayer(RenderObject *object) 0087 : m_object(object), 0088 m_parent(nullptr), 0089 m_previous(nullptr), 0090 m_next(nullptr), 0091 m_first(nullptr), 0092 m_last(nullptr), 0093 m_x(0), 0094 m_y(0), 0095 m_scrollX(0), 0096 m_scrollY(0), 0097 m_scrollXOrigin(0), 0098 m_scrollWidth(0), 0099 m_scrollHeight(0), 0100 m_hBar(nullptr), 0101 m_vBar(nullptr), 0102 m_scrollMediator(nullptr), 0103 m_posZOrderList(nullptr), 0104 m_negZOrderList(nullptr), 0105 m_overflowList(nullptr), 0106 m_zOrderListsDirty(true), 0107 m_overflowListDirty(true), 0108 m_isOverflowOnly(shouldBeOverflowOnly()), 0109 m_markedForRepaint(false), 0110 m_hasOverlaidWidgets(false), 0111 m_visibleContentStatusDirty(true), 0112 m_hasVisibleContent(false), 0113 m_visibleDescendantStatusDirty(false), 0114 m_hasVisibleDescendant(false), 0115 m_inScrollbarRelayout(false), 0116 m_marquee(nullptr) 0117 { 0118 if (!object->firstChild() && object->style()) { 0119 m_visibleContentStatusDirty = false; 0120 m_hasVisibleContent = object->style()->visibility() == VISIBLE; 0121 } 0122 m_buffer[0] = nullptr; 0123 m_buffer[1] = nullptr; 0124 m_wasStackingContext = object->style() ? isStackingContext() : false; 0125 } 0126 0127 RenderLayer::~RenderLayer() 0128 { 0129 // Child layers will be deleted by their corresponding render objects, so 0130 // our destructor doesn't have to do anything. 0131 delete m_hBar; 0132 delete m_vBar; 0133 delete m_buffer[0]; 0134 delete m_buffer[1]; 0135 delete m_scrollMediator; 0136 delete m_posZOrderList; 0137 delete m_negZOrderList; 0138 delete m_overflowList; 0139 delete m_marquee; 0140 } 0141 0142 void RenderLayer::updateLayerPosition() 0143 { 0144 0145 // The canvas is sized to the docWidth/Height over in RenderCanvas::layout, so we 0146 // don't need to ever update our layer position here. 0147 if (renderer()->isCanvas()) { 0148 return; 0149 } 0150 0151 int x = m_object->xPos(); 0152 int y = m_object->yPos() - m_object->borderTopExtra(); 0153 0154 if (!m_object->isPositioned()) { 0155 // We must adjust our position by walking up the render tree looking for the 0156 // nearest enclosing object with a layer. 0157 RenderObject *curr = m_object->parent(); 0158 while (curr && !curr->layer()) { 0159 x += curr->xPos(); 0160 y += curr->yPos(); 0161 curr = curr->parent(); 0162 } 0163 if (curr) { 0164 y += curr->borderTopExtra(); 0165 } 0166 } 0167 0168 if (m_object->isRelPositioned()) { 0169 static_cast<RenderBox *>(m_object)->relativePositionOffset(x, y); 0170 } 0171 0172 // Subtract our parent's scroll offset. 0173 if (m_object->isPositioned() && enclosingPositionedAncestor()) { 0174 RenderLayer *positionedParent = enclosingPositionedAncestor(); 0175 0176 // For positioned layers, we subtract out the enclosing positioned layer's scroll offset. 0177 positionedParent->subtractScrollOffset(x, y); 0178 positionedParent->checkInlineRelOffset(m_object, x, y); 0179 } else if (parent()) { 0180 parent()->subtractScrollOffset(x, y); 0181 } 0182 0183 setPos(x, y); 0184 } 0185 0186 QRegion RenderLayer::paintedRegion(RenderLayer *rootLayer) 0187 { 0188 updateZOrderLists(); 0189 QRegion r; 0190 const RenderStyle *s = renderer()->style(); 0191 bool isTrans = (s->opacity() < 1.0); 0192 if (isTrans && m_hasVisibleDescendant) { 0193 if (!s->opacity()) { 0194 return r; 0195 } 0196 for (RenderLayer *ch = firstChild(); ch; ch = ch->nextSibling()) { 0197 r += ch->paintedRegion(rootLayer); 0198 } 0199 } else if (m_negZOrderList && m_hasVisibleDescendant) { 0200 uint count = m_negZOrderList->count(); 0201 for (uint i = 0; i < count; i++) { 0202 RenderLayer *child = m_negZOrderList->at(i); 0203 r += child->paintedRegion(rootLayer); 0204 } 0205 } 0206 0207 if (m_hasVisibleContent) { 0208 int x = 0; int y = 0; 0209 convertToLayerCoords(rootLayer, x, y); 0210 QRect cr(x, y, width(), height()); 0211 if (s->visibility() == VISIBLE && (s->backgroundImage() || s->backgroundColor().isValid() || s->hasBorder() || 0212 renderer()->scrollsOverflow() || renderer()->isReplaced())) { 0213 if (!s->hidesOverflow()) { 0214 r += renderer()->visibleFlowRegion(x, y); 0215 } 0216 r += cr; 0217 } else { 0218 r += renderer()->visibleFlowRegion(x, y); 0219 } 0220 } 0221 0222 if (!isTrans && m_posZOrderList && m_hasVisibleDescendant) { 0223 uint count = m_posZOrderList->count(); 0224 for (uint i = 0; i < count; i++) { 0225 RenderLayer *child = m_posZOrderList->at(i); 0226 r += child->paintedRegion(rootLayer); 0227 } 0228 } 0229 return r; 0230 } 0231 0232 void RenderLayer::repaint(Priority p, bool markForRepaint) 0233 { 0234 if (markForRepaint && m_markedForRepaint) { 0235 return; 0236 } 0237 for (RenderLayer *child = firstChild(); child; child = child->nextSibling()) { 0238 child->repaint(p, markForRepaint); 0239 } 0240 QRect layerBounds, damageRect, fgrect; 0241 calculateRects(renderer()->canvas()->layer(), renderer()->viewRect(), layerBounds, damageRect, fgrect); 0242 m_visibleRect = damageRect.intersected(layerBounds); 0243 if (m_visibleRect.isValid()) { 0244 renderer()->canvas()->repaintViewRectangle(m_visibleRect.x(), m_visibleRect.y(), m_visibleRect.width(), m_visibleRect.height(), (p > NormalPriority)); 0245 } 0246 if (markForRepaint) { 0247 m_markedForRepaint = true; 0248 } 0249 } 0250 0251 void RenderLayer::updateLayerPositions(RenderLayer *rootLayer, bool doFullRepaint, bool checkForRepaint) 0252 { 0253 if (doFullRepaint) { 0254 m_object->repaint(); 0255 checkForRepaint = doFullRepaint = false; 0256 } 0257 0258 updateLayerPosition(); // For relpositioned layers or non-positioned layers, 0259 // we need to keep in sync, since we may have shifted relative 0260 // to our parent layer. 0261 0262 if (m_hBar || m_vBar) { 0263 // Need to position the scrollbars. 0264 int x = 0; 0265 int y = 0; 0266 convertToLayerCoords(rootLayer, x, y); 0267 QRect layerBounds = QRect(x, y, width(), height()); 0268 positionScrollbars(layerBounds); 0269 } 0270 0271 updateVisibilityStatus(); 0272 0273 if (m_hasVisibleContent && checkForRepaint && m_markedForRepaint) { 0274 QRect layerBounds, damageRect, fgrect; 0275 calculateRects(rootLayer, renderer()->viewRect(), layerBounds, damageRect, fgrect); 0276 QRect vr = damageRect.intersected(layerBounds); 0277 if (vr != m_visibleRect && vr.isValid()) { 0278 renderer()->canvas()->repaintViewRectangle(vr.x(), vr.y(), vr.width(), vr.height()); 0279 m_visibleRect = vr; 0280 } 0281 } 0282 m_markedForRepaint = false; 0283 0284 for (RenderLayer *child = firstChild(); child; child = child->nextSibling()) { 0285 child->updateLayerPositions(rootLayer, doFullRepaint, checkForRepaint); 0286 } 0287 0288 // With all our children positioned, now update our marquee if we need to. 0289 if (m_marquee) { 0290 m_marquee->updateMarqueePosition(); 0291 } 0292 } 0293 0294 void RenderLayer::setHasVisibleContent(bool b) 0295 { 0296 if (m_hasVisibleContent == b && !m_visibleContentStatusDirty) { 0297 return; 0298 } 0299 m_visibleContentStatusDirty = false; 0300 m_hasVisibleContent = b; 0301 if (m_hasVisibleContent) { 0302 // ### dirty painted region 0303 // m_region = QRegion(); 0304 if (!isOverflowOnly()) 0305 if (RenderLayer *sc = stackingContext()) { 0306 sc->dirtyZOrderLists(); 0307 } 0308 } 0309 if (parent()) { 0310 parent()->childVisibilityChanged(m_hasVisibleContent); 0311 } 0312 } 0313 0314 void RenderLayer::dirtyVisibleContentStatus() 0315 { 0316 m_visibleContentStatusDirty = true; 0317 if (parent()) { 0318 parent()->dirtyVisibleDescendantStatus(); 0319 } 0320 } 0321 0322 void RenderLayer::childVisibilityChanged(bool newVisibility) 0323 { 0324 if (m_hasVisibleDescendant == newVisibility || m_visibleDescendantStatusDirty) { 0325 return; 0326 } 0327 if (newVisibility) { 0328 RenderLayer *l = this; 0329 while (l && !l->m_visibleDescendantStatusDirty && !l->m_hasVisibleDescendant) { 0330 l->m_hasVisibleDescendant = true; 0331 l = l->parent(); 0332 } 0333 } else { 0334 dirtyVisibleDescendantStatus(); 0335 } 0336 } 0337 0338 void RenderLayer::dirtyVisibleDescendantStatus() 0339 { 0340 RenderLayer *l = this; 0341 while (l && !l->m_visibleDescendantStatusDirty) { 0342 l->m_visibleDescendantStatusDirty = true; 0343 l = l->parent(); 0344 } 0345 } 0346 0347 void RenderLayer::updateVisibilityStatus() 0348 { 0349 if (m_visibleDescendantStatusDirty) { 0350 m_hasVisibleDescendant = false; 0351 for (RenderLayer *child = firstChild(); child; child = child->nextSibling()) { 0352 child->updateVisibilityStatus(); 0353 if (child->m_hasVisibleContent || child->m_hasVisibleDescendant) { 0354 m_hasVisibleDescendant = true; 0355 break; 0356 } 0357 } 0358 m_visibleDescendantStatusDirty = false; 0359 } 0360 0361 if (m_visibleContentStatusDirty) { 0362 if (m_object->style()->visibility() == VISIBLE) { 0363 m_hasVisibleContent = true; 0364 } else { 0365 // layer may be hidden but still have some visible content, check for this 0366 m_hasVisibleContent = false; 0367 RenderObject *r = m_object->firstChild(); 0368 while (r) { 0369 if (r->style()->visibility() == VISIBLE && !r->layer()) { 0370 m_hasVisibleContent = true; 0371 break; 0372 } 0373 if (r->firstChild() && !r->layer()) { 0374 r = r->firstChild(); 0375 } else if (r->nextSibling()) { 0376 r = r->nextSibling(); 0377 } else { 0378 do { 0379 r = r->parent(); 0380 if (r == m_object) { 0381 r = nullptr; 0382 } 0383 } while (r && !r->nextSibling()); 0384 if (r) { 0385 r = r->nextSibling(); 0386 } 0387 } 0388 } 0389 } 0390 m_visibleContentStatusDirty = false; 0391 } 0392 } 0393 0394 void RenderLayer::updateWidgetMasks(RenderLayer *rootLayer) 0395 { 0396 if (hasOverlaidWidgets() && !renderer()->canvas()->pagedMode()) { 0397 updateZOrderLists(); 0398 uint count = m_posZOrderList ? m_posZOrderList->count() : 0; 0399 bool needUpdate = false; 0400 KHTMLView *sa = nullptr; 0401 if (count > 0) { 0402 sa = m_object->document()->view(); 0403 m_region = QRect(0, 0, sa->contentsWidth(), sa->contentsHeight()); 0404 for (uint i = 0; i < count; i++) { 0405 RenderLayer *child = m_posZOrderList->at(i); 0406 if (child->zIndex() == 0 && child->renderer()->style()->position() == PSTATIC) { 0407 continue; // we don't know the widget's exact stacking position within flow 0408 } 0409 m_region -= child->paintedRegion(rootLayer); 0410 } 0411 needUpdate = true; 0412 } 0413 RenderLayer *sc = this; 0414 int zx = zIndex(); 0415 while ((sc = sc->stackingContext())) { 0416 sc->updateZOrderLists(); 0417 bool found = false; 0418 if (zx < 0) { 0419 count = sc->m_negZOrderList ? sc->m_negZOrderList->count() : 0; 0420 needUpdate = needUpdate || count > 0; 0421 for (uint i = 0; i < count; i++) { 0422 found = found || sc->m_negZOrderList->at(i)->zIndex() > zx; 0423 if (found) { 0424 if (!sa) { 0425 sa = m_object->document()->view(); 0426 m_region = QRect(0, 0, sa->contentsWidth(), sa->contentsHeight()); 0427 } 0428 m_region -= sc->m_negZOrderList->at(i)->paintedRegion(rootLayer); 0429 } 0430 } 0431 } 0432 count = sc->m_posZOrderList ? sc->m_posZOrderList->count() : 0; 0433 if (count > 0) { 0434 needUpdate = true; 0435 for (uint i = 0; i < count; i++) { 0436 found = found || sc->m_posZOrderList->at(i)->zIndex() > zx; 0437 if (found) { 0438 if (!sa) { 0439 sa = m_object->document()->view(); 0440 m_region = QRect(0, 0, sa->contentsWidth(), sa->contentsHeight()); 0441 } 0442 m_region -= sc->m_posZOrderList->at(i)->paintedRegion(rootLayer); 0443 } 0444 } 0445 } 0446 zx = sc->zIndex(); 0447 } 0448 if (!needUpdate) { 0449 needUpdate = !m_region.isEmpty(); 0450 m_region = QRegion(); 0451 } 0452 if (needUpdate) { 0453 renderer()->updateWidgetMasks(); 0454 } 0455 } 0456 for (RenderLayer *child = firstChild(); child; child = child->nextSibling()) { 0457 child->updateWidgetMasks(rootLayer); 0458 } 0459 } 0460 0461 int RenderLayer::width() const 0462 { 0463 int w = m_object->width(); 0464 if (!m_object->hasOverflowClip()) { 0465 w = qMax(m_object->overflowWidth(), w); 0466 } 0467 return w; 0468 } 0469 0470 int RenderLayer::height() const 0471 { 0472 int h = m_object->height() + m_object->borderTopExtra() + m_object->borderBottomExtra(); 0473 if (!m_object->hasOverflowClip()) { 0474 h = qMax(m_object->overflowHeight(), h); 0475 } 0476 return h; 0477 } 0478 0479 RenderLayer *RenderLayer::stackingContext() const 0480 { 0481 RenderLayer *curr = parent(); 0482 for (; curr && !curr->m_object->isCanvas() && 0483 curr->m_object->style()->hasAutoZIndex(); 0484 curr = curr->parent()) {}; 0485 return curr; 0486 } 0487 0488 RenderLayer *RenderLayer::enclosingPositionedAncestor() const 0489 { 0490 RenderLayer *curr = parent(); 0491 for (; curr && !curr->m_object->isCanvas() && 0492 !curr->m_object->isPositioned() && !curr->m_object->isRelPositioned(); 0493 curr = curr->parent()) {}; 0494 0495 return curr; 0496 } 0497 0498 bool RenderLayer::isTransparent() const 0499 { 0500 return m_object->style()->opacity() < 1.0f; 0501 } 0502 0503 RenderLayer *RenderLayer::transparentAncestor() const 0504 { 0505 RenderLayer *curr = parent(); 0506 for (; curr && curr->m_object->style()->opacity() == 1.0f; curr = curr->parent()) {}; 0507 return curr; 0508 } 0509 0510 void *RenderLayer::operator new(size_t sz, RenderArena *renderArena) throw() 0511 { 0512 return renderArena->allocate(sz); 0513 } 0514 0515 void RenderLayer::operator delete(void *ptr, size_t sz) 0516 { 0517 assert(inRenderLayerDetach); 0518 #ifdef KHTML_USE_ARENA_ALLOCATOR 0519 // Stash size where detach can find it. 0520 *(size_t *)ptr = sz; 0521 #endif 0522 } 0523 0524 void RenderLayer::detach(RenderArena *renderArena) 0525 { 0526 #ifndef NDEBUG 0527 inRenderLayerDetach = true; 0528 #endif 0529 delete this; 0530 #ifndef NDEBUG 0531 inRenderLayerDetach = false; 0532 #endif 0533 0534 // Recover the size left there for us by operator delete and free the memory. 0535 renderArena->free(*(size_t *)this, this); 0536 } 0537 0538 void RenderLayer::addChild(RenderLayer *child, RenderLayer *beforeChild) 0539 { 0540 RenderLayer *prevSibling = beforeChild ? beforeChild->previousSibling() : lastChild(); 0541 if (prevSibling) { 0542 child->setPreviousSibling(prevSibling); 0543 prevSibling->setNextSibling(child); 0544 } else { 0545 setFirstChild(child); 0546 } 0547 0548 if (beforeChild) { 0549 beforeChild->setPreviousSibling(child); 0550 child->setNextSibling(beforeChild); 0551 } else { 0552 setLastChild(child); 0553 } 0554 0555 child->setParent(this); 0556 0557 if (child->isOverflowOnly()) { 0558 dirtyOverflowList(); 0559 } else { 0560 // Dirty the z-order list in which we are contained. The stackingContext() can be null in the 0561 // case where we're building up generated content layers. This is ok, since the lists will start 0562 // off dirty in that case anyway. 0563 RenderLayer *stackingContext = child->stackingContext(); 0564 if (stackingContext) { 0565 stackingContext->dirtyZOrderLists(); 0566 } 0567 } 0568 child->updateVisibilityStatus(); 0569 if (child->m_hasVisibleContent || child->m_hasVisibleDescendant) { 0570 childVisibilityChanged(true); 0571 } 0572 } 0573 0574 RenderLayer *RenderLayer::removeChild(RenderLayer *oldChild) 0575 { 0576 // remove the child 0577 if (oldChild->previousSibling()) { 0578 oldChild->previousSibling()->setNextSibling(oldChild->nextSibling()); 0579 } 0580 if (oldChild->nextSibling()) { 0581 oldChild->nextSibling()->setPreviousSibling(oldChild->previousSibling()); 0582 } 0583 0584 if (m_first == oldChild) { 0585 m_first = oldChild->nextSibling(); 0586 } 0587 if (m_last == oldChild) { 0588 m_last = oldChild->previousSibling(); 0589 } 0590 0591 if (oldChild->isOverflowOnly()) { 0592 dirtyOverflowList(); 0593 } else { 0594 // Dirty the z-order list in which we are contained. When called via the 0595 // reattachment process in removeOnlyThisLayer, the layer may already be disconnected 0596 // from the main layer tree, so we need to null-check the |stackingContext| value. 0597 RenderLayer *stackingContext = oldChild->stackingContext(); 0598 if (stackingContext) { 0599 stackingContext->dirtyZOrderLists(); 0600 } 0601 } 0602 0603 oldChild->setPreviousSibling(nullptr); 0604 oldChild->setNextSibling(nullptr); 0605 oldChild->setParent(nullptr); 0606 0607 oldChild->updateVisibilityStatus(); 0608 if (oldChild->m_hasVisibleContent || oldChild->m_hasVisibleDescendant) { 0609 childVisibilityChanged(false); 0610 } 0611 0612 return oldChild; 0613 } 0614 0615 void RenderLayer::removeOnlyThisLayer() 0616 { 0617 if (!m_parent) { 0618 return; 0619 } 0620 0621 // Remove us from the parent. 0622 RenderLayer *parent = m_parent; 0623 RenderLayer *nextSib = nextSibling(); 0624 parent->removeChild(this); 0625 0626 // Now walk our kids and reattach them to our parent. 0627 RenderLayer *current = m_first; 0628 while (current) { 0629 RenderLayer *next = current->nextSibling(); 0630 removeChild(current); 0631 parent->addChild(current, nextSib); 0632 current = next; 0633 } 0634 0635 detach(renderer()->renderArena()); 0636 } 0637 0638 void RenderLayer::insertOnlyThisLayer() 0639 { 0640 if (!m_parent && renderer()->parent()) { 0641 // We need to connect ourselves when our renderer() has a parent. 0642 // Find our enclosingLayer and add ourselves. 0643 RenderLayer *parentLayer = renderer()->parent()->enclosingLayer(); 0644 if (parentLayer) 0645 parentLayer->addChild(this, 0646 renderer()->parent()->findNextLayer(parentLayer, renderer())); 0647 } 0648 0649 // Remove all descendant layers from the hierarchy and add them to the new position. 0650 for (RenderObject *curr = renderer()->firstChild(); curr; curr = curr->nextSibling()) { 0651 curr->moveLayers(m_parent, this); 0652 } 0653 } 0654 0655 void RenderLayer::convertToLayerCoords(const RenderLayer *ancestorLayer, int &x, int &y) const 0656 { 0657 if (ancestorLayer == this) { 0658 return; 0659 } 0660 0661 if (m_object->style()->position() == PFIXED) { 0662 // Add in the offset of the view. We can obtain this by calling 0663 // absolutePosition() on the RenderCanvas. 0664 int xOff, yOff; 0665 m_object->absolutePosition(xOff, yOff, true); 0666 x += xOff; 0667 y += yOff; 0668 return; 0669 } 0670 0671 RenderLayer *parentLayer; 0672 if (m_object->style()->position() == PABSOLUTE) { 0673 parentLayer = enclosingPositionedAncestor(); 0674 } else { 0675 parentLayer = parent(); 0676 } 0677 0678 if (!parentLayer) { 0679 return; 0680 } 0681 0682 parentLayer->convertToLayerCoords(ancestorLayer, x, y); 0683 0684 x += xPos(); 0685 y += yPos(); 0686 } 0687 0688 void RenderLayer::scrollOffset(int &x, int &y) 0689 { 0690 x += scrollXOffset(); 0691 y += scrollYOffset(); 0692 } 0693 0694 void RenderLayer::subtractScrollOffset(int &x, int &y) 0695 { 0696 x -= scrollXOffset(); 0697 y -= scrollYOffset(); 0698 } 0699 0700 void RenderLayer::checkInlineRelOffset(const RenderObject *o, int &x, int &y) 0701 { 0702 if (o->style()->position() != PABSOLUTE || !renderer()->isRelPositioned() || !renderer()->isInlineFlow()) { 0703 return; 0704 } 0705 0706 // Our renderer is an enclosing relpositioned inline, we need to add in the offset of the first line 0707 // box from the rest of the content, but only in the cases where we know our descendant is positioned 0708 // relative to the inline itself. 0709 assert(o->container() == m_object); 0710 0711 RenderFlow *flow = static_cast<RenderFlow *>(m_object); 0712 int sx = 0, sy = 0; 0713 if (flow->firstLineBox()) { 0714 if (flow->style()->direction() == LTR) { 0715 sx = flow->firstLineBox()->xPos(); 0716 } else { 0717 sx = flow->lastLineBox()->xPos(); 0718 } 0719 sy = flow->firstLineBox()->yPos(); 0720 } else { 0721 sx = flow->staticX(); // ### 0722 sy = flow->staticY(); 0723 } 0724 bool isInlineType = o->style()->isOriginalDisplayInlineType(); 0725 0726 if (!o->hasStaticX()) { 0727 x += sx; 0728 } 0729 0730 // Despite the positioned child being a block display type inside an inline, we still keep 0731 // its x locked to our left. Arguably the correct behavior would be to go flush left to 0732 // the block that contains us, but that isn't what other browsers do. 0733 if (o->hasStaticX() && !isInlineType) 0734 // Avoid adding in the left border/padding of the containing block twice. Subtract it out. 0735 { 0736 x += sx - (o->containingBlock()->borderLeft() + o->containingBlock()->paddingLeft()); 0737 } 0738 0739 if (!o->hasStaticY()) { 0740 y += sy; 0741 } 0742 } 0743 0744 void RenderLayer::scrollToOffset(int x, int y, bool updateScrollbars, bool repaint, bool dispatchEvent) 0745 { 0746 assert(!renderer()->canvas()->isPerformingLayout() || !dispatchEvent); 0747 if (renderer()->style()->overflowX() != OMARQUEE || !renderer()->hasOverflowClip()) { 0748 if (x < 0) { 0749 x = 0; 0750 } 0751 if (y < 0) { 0752 y = 0; 0753 } 0754 0755 // Call the scrollWidth/Height functions so that the dimensions will be computed if they need 0756 // to be (for overflow:hidden blocks). 0757 // ### merge the scrollWidth()/scrollHeight() methods 0758 int maxX = m_scrollWidth - m_object->clientWidth(); 0759 int maxY = m_scrollHeight - m_object->clientHeight(); 0760 0761 if (x > maxX) { 0762 x = maxX; 0763 } 0764 if (y > maxY) { 0765 y = maxY; 0766 } 0767 } 0768 0769 if ((m_scrollX == x - m_scrollXOrigin) && m_scrollY == y) { 0770 return; // nothing to do 0771 } 0772 0773 // FIXME: Eventually, we will want to perform a blit. For now never 0774 // blit, since the check for blitting is going to be very 0775 // complicated (since it will involve testing whether our layer 0776 // is either occluded by another layer or clipped by an enclosing 0777 // layer or contains fixed backgrounds, etc.). 0778 m_scrollX = x - m_scrollXOrigin; 0779 m_scrollY = y; 0780 0781 // Update the positions of our child layers. 0782 RenderLayer *rootLayer = root(); 0783 for (RenderLayer *child = firstChild(); child; child = child->nextSibling()) { 0784 child->updateLayerPositions(rootLayer); 0785 } 0786 0787 // Just schedule a full repaint of our object. 0788 if (repaint) { 0789 m_object->repaint(RealtimePriority); 0790 } 0791 0792 if (updateScrollbars) { 0793 if (m_hBar) { 0794 m_hBar->setValue(scrollXOffset()); 0795 } 0796 if (m_vBar) { 0797 m_vBar->setValue(m_scrollY); 0798 } 0799 } 0800 0801 if (!dispatchEvent) { 0802 return; 0803 } 0804 0805 // Fire the scroll DOM event. Do this the very last thing, since the handler may kill us. 0806 m_object->element()->dispatchHTMLEvent(EventImpl::SCROLL_EVENT, false, false); 0807 } 0808 0809 void RenderLayer::updateScrollPositionFromScrollbars() 0810 { 0811 bool needUpdate = false; 0812 int newX = m_scrollX; 0813 int newY = m_scrollY; 0814 0815 if (m_hBar) { 0816 bool rtl = (m_hBar->layoutDirection() == Qt::RightToLeft); 0817 newX = rtl ? m_hBar->maximum() - m_hBar->value() : m_hBar->value(); 0818 if (newX != m_scrollX) { 0819 needUpdate = true; 0820 } 0821 } 0822 0823 if (m_vBar) { 0824 newY = m_vBar->value(); 0825 if (newY != m_scrollY) { 0826 needUpdate = true; 0827 } 0828 } 0829 0830 if (needUpdate) { 0831 scrollToOffset(newX, newY, false); 0832 } 0833 } 0834 0835 void 0836 RenderLayer::showScrollbar(Qt::Orientation o, bool show) 0837 { 0838 ScrollBarWidget *sb = (o == Qt::Horizontal) ? m_hBar : m_vBar; 0839 0840 if (show && !sb) { 0841 KHTMLView *view = m_object->document()->view(); 0842 sb = new ScrollBarWidget(o, view->widget()); 0843 sb->move(0, -50000); 0844 sb->setAttribute(Qt::WA_NoSystemBackground); 0845 sb->show(); 0846 if (!m_scrollMediator) { 0847 m_scrollMediator = new RenderScrollMediator(this); 0848 } 0849 m_scrollMediator->connect(sb, SIGNAL(valueChanged(int)), SLOT(slotValueChanged())); 0850 } else if (!show && sb) { 0851 delete sb; 0852 sb = nullptr; 0853 } 0854 0855 if (o == Qt::Horizontal) { 0856 m_hBar = sb; 0857 } else { 0858 m_vBar = sb; 0859 } 0860 } 0861 0862 bool RenderLayer::hasReversedScrollbar() const 0863 { 0864 if (!m_vBar) { 0865 return false; 0866 } 0867 return (m_vBar->layoutDirection() == Qt::RightToLeft); 0868 } 0869 0870 int RenderLayer::verticalScrollbarWidth() 0871 { 0872 if (!m_vBar) { 0873 return 0; 0874 } 0875 0876 #ifdef APPLE_CHANGES 0877 return m_vBar->width(); 0878 #else 0879 return m_vBar->style()->pixelMetric(QStyle::PM_ScrollBarExtent); 0880 #endif 0881 0882 } 0883 0884 int RenderLayer::horizontalScrollbarHeight() 0885 { 0886 if (!m_hBar) { 0887 return 0; 0888 } 0889 0890 #ifdef APPLE_CHANGES 0891 return m_hBar->height(); 0892 #else 0893 return m_hBar->style()->pixelMetric(QStyle::PM_ScrollBarExtent); 0894 #endif 0895 0896 } 0897 0898 void RenderLayer::positionScrollbars(const QRect &absBounds) 0899 { 0900 #ifdef APPLE_CHANGES 0901 if (m_vBar) { 0902 view->addChild(m_vBar, absBounds.x() + absBounds.width() - m_object->borderRight() - m_vBar->width(), 0903 absBounds.y() + m_object->borderTop()); 0904 m_vBar->resize(m_vBar->width(), absBounds.height() - 0905 (m_object->borderTop() + m_object->borderBottom()) - 0906 (m_hBar ? m_hBar->height() - 1 : 0)); 0907 } 0908 0909 if (m_hBar) { 0910 view->addChild(m_hBar, absBounds.x() + m_object->borderLeft(), 0911 absBounds.y() + absBounds.height() - m_object->borderBottom() - m_hBar->height()); 0912 m_hBar->resize(absBounds.width() - (m_object->borderLeft() + m_object->borderRight()) - 0913 (m_vBar ? m_vBar->width() - 1 : 0), m_hBar->height()); 0914 } 0915 #else 0916 int tx = absBounds.x(); 0917 int ty = absBounds.y(); 0918 int bl = m_object->borderLeft(); 0919 int bt = m_object->borderTop(); 0920 int w = width() - bl - m_object->borderRight(); 0921 int h = height() - bt - m_object->borderBottom(); 0922 0923 if (w <= 0 || h <= 0 || (!m_vBar && !m_hBar)) { 0924 return; 0925 } 0926 0927 tx += bl; 0928 ty += bt; 0929 0930 ScrollBarWidget *b = m_hBar; 0931 if (!m_hBar) { 0932 b = m_vBar; 0933 } 0934 int sw = b->style()->pixelMetric(QStyle::PM_ScrollBarExtent); 0935 bool rtl = b->layoutDirection() == Qt::RightToLeft; 0936 0937 if (m_vBar) { 0938 QRect vBarRect = QRect(tx + (rtl ? 0 : w - sw), ty, sw, h - (m_hBar ? sw : 0)); 0939 m_vBar->resize(vBarRect.width(), vBarRect.height()); 0940 m_vBar->m_kwp->setPos(QPoint(vBarRect.x(), vBarRect.y())); 0941 } 0942 0943 if (m_hBar) { 0944 QRect hBarRect = QRect(tx + (rtl && m_vBar ? sw : 0), ty + h - sw, w - (!rtl && m_vBar ? sw : 0), sw); 0945 m_hBar->resize(hBarRect.width(), hBarRect.height()); 0946 m_hBar->m_kwp->setPos(QPoint(hBarRect.x(), hBarRect.y())); 0947 } 0948 #endif 0949 } 0950 0951 #define LINE_STEP 10 0952 #define PAGE_KEEP 40 0953 0954 void RenderLayer::checkScrollbarsAfterLayout() 0955 { 0956 int rightPos = m_object->rightmostPosition(true); 0957 int bottomPos = m_object->lowestPosition(true); 0958 0959 /* TODO 0960 m_scrollLeft = m_object->leftmostPosition(true); 0961 m_scrollTop = m_object->highestPosition(true); 0962 */ 0963 0964 int clientWidth = m_object->clientWidth(); 0965 int clientHeight = m_object->clientHeight(); 0966 m_scrollWidth = clientWidth; 0967 m_scrollHeight = clientHeight; 0968 0969 if (rightPos - m_object->borderLeft() > m_scrollWidth) { 0970 m_scrollWidth = rightPos - m_object->borderLeft(); 0971 } 0972 if (bottomPos - m_object->borderTop() > m_scrollHeight) { 0973 m_scrollHeight = bottomPos - m_object->borderTop(); 0974 } 0975 0976 m_scrollXOrigin = 0; // ### (m_object->style()->direction() == RTL) ? m_scrollWidth - clientWidth : 0; 0977 0978 bool needHorizontalBar = rightPos > width(); 0979 bool needVerticalBar = bottomPos > height(); 0980 0981 bool haveHorizontalBar = m_hBar && m_hBar->isEnabled(); 0982 bool haveVerticalBar = m_vBar && m_vBar->isEnabled(); 0983 0984 bool hasOvf = m_object->hasOverflowClip(); 0985 0986 // overflow:scroll should just enable/disable. 0987 if (m_hBar && hasOvf && m_object->style()->overflowX() == OSCROLL) { 0988 m_hBar->setEnabled(needHorizontalBar); 0989 } 0990 if (m_vBar && hasOvf && m_object->style()->overflowY() == OSCROLL) { 0991 m_vBar->setEnabled(needVerticalBar); 0992 } 0993 0994 // Sometimes we originally had a scrolling overflow, but it got changed to 0995 // hidden/visible. 0996 bool deadScrollX = m_hBar && !m_object->scrollsOverflowX(); 0997 bool deadScrollY = m_vBar && !m_object->scrollsOverflowY(); 0998 0999 // 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 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 1095 void RenderLayer::paint(QPainter *p, const QRect &damageRect, bool selectionOnly) 1096 { 1097 paintLayer(this, p, damageRect, selectionOnly); 1098 } 1099 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 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 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 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 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 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 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 1459 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 1467 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. 1475 static RenderObject *hoverAncestor(RenderObject *obj) 1476 { 1477 return (!obj->isInline() && obj->continuation()) ? obj->continuation() : obj->parent(); 1478 } 1479 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 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). 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 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 1636 void RenderLayer::dirtyOverflowList() 1637 { 1638 if (m_overflowList) { 1639 m_overflowList->clear(); 1640 } 1641 m_overflowListDirty = true; 1642 } 1643 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 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 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 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 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 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 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 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 1812 bool RenderLayer::shouldBeOverflowOnly() const 1813 { 1814 return renderer()->style() && renderer()->hasOverflowClip() && 1815 !renderer()->isPositioned() && !renderer()->isRelPositioned() && !isTransparent(); 1816 } 1817 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 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 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 1885 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 1896 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 1922 bool Marquee::isHorizontal() const 1923 { 1924 return direction() == MLEFT || direction() == MRIGHT; 1925 } 1926 1927 bool Marquee::isUnfurlMarquee() const 1928 { 1929 EMarqueeBehavior behavior = m_layer->renderer()->style()->marqueeBehavior(); 1930 return (behavior == MUNFURL); 1931 } 1932 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 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 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 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 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 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 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 #include "moc_render_layer.cpp"