1 /* 2 * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved. 3 * 4 * Portions are Copyright (C) 1998 Netscape Communications Corporation. 5 * 6 * Other contributors: 7 * Robert O'Callahan <roc+@cs.cmu.edu> 8 * David Baron <dbaron (at) fas.harvard.edu> 9 * Christian Biesinger <cbiesinger (at) web.de> 10 * Randall Jesup <rjesup (at) wgate.com> 11 * Roland Mainz <roland.mainz (at) informatik.med.uni-giessen.de> 12 * Josh Soref <timeless (at) mac.com> 13 * Boris Zbarsky <bzbarsky (at) mit.edu> 14 * 15 * This library is free software; you can redistribute it and/or 16 * modify it under the terms of the GNU Lesser General Public 17 * License as published by the Free Software Foundation; either 18 * version 2.1 of the License, or (at your option) any later version. 19 * 20 * This library is distributed in the hope that it will be useful, 21 * but WITHOUT ANY WARRANTY; without even the implied warranty of 22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 23 * Lesser General Public License for more details. 24 * 25 * You should have received a copy of the GNU Lesser General Public 26 * License along with this library; if not, write to the Free Software 27 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 28 * 29 * Alternatively, the contents of this file may be used under the terms 30 * of either the Mozilla Public License Version 1.1, found at 31 * http://www.mozilla.org/MPL/ (the "MPL") or the GNU General Public 32 * License Version 2.0, found at http://www.fsf.org/copyleft/gpl.html 33 * (the "GPL"), in which case the provisions of the MPL or the GPL are 34 * applicable instead of those above. If you wish to allow use of your 35 * version of this file only under the terms of one of those two 36 * licenses (the MPL or the GPL) and not to allow others to use your 37 * version of this file under the LGPL, indicate your decision by 38 * deletingthe provisions above and replace them with the notice and 39 * other provisions required by the MPL or the GPL, as the case may be. 40 * If you do not delete the provisions above, a recipient may use your 41 * version of this file under any of the LGPL, the MPL or the GPL. 42 */ 43 44 #include "config.h" 45 #include "RenderLayer.h" 46 47 #include "CString.h" 48 #include "CSSPropertyNames.h" 49 #include "CSSStyleDeclaration.h" 50 #include "CSSStyleSelector.h" 51 #include "Document.h" 52 #include "EventHandler.h" 53 #include "EventNames.h" 54 #include "FloatPoint3D.h" 55 #include "FloatRect.h" 56 #include "FocusController.h" 57 #include "Frame.h" 58 #include "FrameTree.h" 59 #include "FrameView.h" 60 #include "Gradient.h" 61 #include "GraphicsContext.h" 62 #include "HTMLNames.h" 63 #include "HitTestRequest.h" 64 #include "HitTestResult.h" 65 #include "OverflowEvent.h" 66 #include "OverlapTestRequestClient.h" 67 #include "Page.h" 68 #include "PlatformMouseEvent.h" 69 #include "RenderArena.h" 70 #include "RenderInline.h" 71 #include "RenderMarquee.h" 72 #include "RenderReplica.h" 73 #include "RenderScrollbar.h" 74 #include "RenderScrollbarPart.h" 75 #include "RenderTheme.h" 76 #include "RenderTreeAsText.h" 77 #include "RenderView.h" 78 #include "ScaleTransformOperation.h" 79 #include "Scrollbar.h" 80 #include "ScrollbarTheme.h" 81 #include "SelectionController.h" 82 #include "TextStream.h" 83 #include "TransformationMatrix.h" 84 #include "TransformState.h" 85 #include "TranslateTransformOperation.h" 86 #include <wtf/StdLibExtras.h> 87 #include <wtf/UnusedParam.h> 88 89 #if USE(ACCELERATED_COMPOSITING) 90 #include "RenderLayerBacking.h" 91 #include "RenderLayerCompositor.h" 92 #endif 93 94 #if ENABLE(SVG) 95 #include "SVGNames.h" 96 #endif 97 98 #define MIN_INTERSECT_FOR_REVEAL 32 99 100 using namespace std; 101 102 namespace WebCore { 103 104 using namespace HTMLNames; 105 106 const int MinimumWidthWhileResizing = 100; 107 const int MinimumHeightWhileResizing = 40; 108 109 void* ClipRects::operator new(size_t sz, RenderArena* renderArena) throw() 110 { 111 return renderArena->allocate(sz); 112 } 113 114 void ClipRects::operator delete(void* ptr, size_t sz) 115 { 116 // Stash size where destroy can find it. 117 *(size_t *)ptr = sz; 118 } 119 120 void ClipRects::destroy(RenderArena* renderArena) 121 { 122 delete this; 123 124 // Recover the size left there for us by operator delete and free the memory. 125 renderArena->free(*(size_t *)this, this); 126 } 127 128 RenderLayer::RenderLayer(RenderBoxModelObject* renderer) 129 : m_renderer(renderer) 130 , m_parent(0) 131 , m_previous(0) 132 , m_next(0) 133 , m_first(0) 134 , m_last(0) 135 , m_relX(0) 136 , m_relY(0) 137 , m_x(0) 138 , m_y(0) 139 , m_width(0) 140 , m_height(0) 141 , m_scrollX(0) 142 , m_scrollY(0) 143 , m_scrollOriginX(0) 144 , m_scrollLeftOverflow(0) 145 , m_scrollWidth(0) 146 , m_scrollHeight(0) 147 , m_inResizeMode(false) 148 , m_posZOrderList(0) 149 , m_negZOrderList(0) 150 , m_normalFlowList(0) 151 , m_clipRects(0) 152 #ifndef NDEBUG 153 , m_clipRectsRoot(0) 154 #endif 155 , m_scrollDimensionsDirty(true) 156 , m_zOrderListsDirty(true) 157 , m_normalFlowListDirty(true) 158 , m_isNormalFlowOnly(shouldBeNormalFlowOnly()) 159 , m_usedTransparency(false) 160 , m_paintingInsideReflection(false) 161 , m_inOverflowRelayout(false) 162 , m_needsFullRepaint(false) 163 , m_overflowStatusDirty(true) 164 , m_visibleContentStatusDirty(true) 165 , m_hasVisibleContent(false) 166 , m_visibleDescendantStatusDirty(false) 167 , m_hasVisibleDescendant(false) 168 , m_3DTransformedDescendantStatusDirty(true) 169 , m_has3DTransformedDescendant(false) 170 #if USE(ACCELERATED_COMPOSITING) 171 , m_hasCompositingDescendant(false) 172 , m_mustOverlapCompositedLayers(false) 173 #endif 174 , m_marquee(0) 175 , m_staticX(0) 176 , m_staticY(0) 177 , m_reflection(0) 178 , m_scrollCorner(0) 179 , m_resizer(0) 180 { 181 if (!renderer->firstChild() && renderer->style()) { 182 m_visibleContentStatusDirty = false; 183 m_hasVisibleContent = renderer->style()->visibility() == VISIBLE; 184 } 185 } 186 187 RenderLayer::~RenderLayer() 188 { 189 if (inResizeMode() && !renderer()->documentBeingDestroyed()) { 190 if (Frame* frame = renderer()->document()->frame()) 191 frame->eventHandler()->resizeLayerDestroyed(); 192 } 193 194 destroyScrollbar(HorizontalScrollbar); 195 destroyScrollbar(VerticalScrollbar); 196 197 // Child layers will be deleted by their corresponding render objects, so 198 // we don't need to delete them ourselves. 199 200 delete m_posZOrderList; 201 delete m_negZOrderList; 202 delete m_normalFlowList; 203 delete m_marquee; 204 205 #if USE(ACCELERATED_COMPOSITING) 206 clearBacking(); 207 #endif 208 209 // Make sure we have no lingering clip rects. 210 ASSERT(!m_clipRects); 211 212 if (m_reflection) 213 removeReflection(); 214 215 if (m_scrollCorner) 216 m_scrollCorner->destroy(); 217 if (m_resizer) 218 m_resizer->destroy(); 219 } 220 221 #if USE(ACCELERATED_COMPOSITING) 222 RenderLayerCompositor* RenderLayer::compositor() const 223 { 224 ASSERT(renderer()->view()); 225 return renderer()->view()->compositor(); 226 } 227 228 void RenderLayer::rendererContentChanged() 229 { 230 // This can get called when video becomes accelerated, so the layers may change. 231 if (compositor()->updateLayerCompositingState(this)) 232 compositor()->setCompositingLayersNeedRebuild(); 233 234 if (m_backing) 235 m_backing->rendererContentChanged(); 236 } 237 #endif // USE(ACCELERATED_COMPOSITING) 238 239 bool RenderLayer::hasAcceleratedCompositing() const 240 { 241 #if USE(ACCELERATED_COMPOSITING) 242 return compositor()->hasAcceleratedCompositing(); 243 #else 244 return false; 245 #endif 246 } 247 248 void RenderLayer::updateLayerPositions(UpdateLayerPositionsFlags flags) 249 { 250 if (flags & DoFullRepaint) { 251 renderer()->repaint(); 252 #if USE(ACCELERATED_COMPOSITING) 253 flags &= ~CheckForRepaint; 254 // We need the full repaint to propagate to child layers if we are hardware compositing. 255 if (!compositor()->inCompositingMode()) 256 flags &= ~DoFullRepaint; 257 #else 258 flags &= ~(CheckForRepaint | DoFullRepaint); 259 #endif 260 } 261 262 updateLayerPosition(); // For relpositioned layers or non-positioned layers, 263 // we need to keep in sync, since we may have shifted relative 264 // to our parent layer. 265 266 int x = 0; 267 int y = 0; 268 convertToLayerCoords(root(), x, y); 269 positionOverflowControls(x, y); 270 271 updateVisibilityStatus(); 272 273 updateTransform(); 274 275 if (m_hasVisibleContent) { 276 RenderView* view = renderer()->view(); 277 ASSERT(view); 278 // FIXME: Optimize using LayoutState and remove the disableLayoutState() call 279 // from updateScrollInfoAfterLayout(). 280 ASSERT(!view->layoutStateEnabled()); 281 282 RenderBoxModelObject* repaintContainer = renderer()->containerForRepaint(); 283 IntRect newRect = renderer()->clippedOverflowRectForRepaint(repaintContainer); 284 IntRect newOutlineBox = renderer()->outlineBoundsForRepaint(repaintContainer); 285 if (flags & CheckForRepaint) { 286 if (view && !view->printing()) { 287 if (m_needsFullRepaint) { 288 renderer()->repaintUsingContainer(repaintContainer, m_repaintRect); 289 if (newRect != m_repaintRect) 290 renderer()->repaintUsingContainer(repaintContainer, newRect); 291 } else 292 renderer()->repaintAfterLayoutIfNeeded(repaintContainer, m_repaintRect, m_outlineBox); 293 } 294 } 295 m_repaintRect = newRect; 296 m_outlineBox = newOutlineBox; 297 } else { 298 m_repaintRect = IntRect(); 299 m_outlineBox = IntRect(); 300 } 301 302 m_needsFullRepaint = false; 303 304 // Go ahead and update the reflection's position and size. 305 if (m_reflection) 306 m_reflection->layout(); 307 308 #if USE(ACCELERATED_COMPOSITING) 309 // Clear the IsCompositingUpdateRoot flag once we've found the first compositing layer in this update. 310 bool isUpdateRoot = (flags & IsCompositingUpdateRoot); 311 if (isComposited()) 312 flags &= ~IsCompositingUpdateRoot; 313 #endif 314 315 for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) 316 child->updateLayerPositions(flags); 317 318 #if USE(ACCELERATED_COMPOSITING) 319 if ((flags & UpdateCompositingLayers) && isComposited()) 320 backing()->updateAfterLayout(RenderLayerBacking::CompositingChildren, isUpdateRoot); 321 #endif 322 323 // With all our children positioned, now update our marquee if we need to. 324 if (m_marquee) 325 m_marquee->updateMarqueePosition(); 326 } 327 328 void RenderLayer::computeRepaintRects() 329 { 330 RenderBoxModelObject* repaintContainer = renderer()->containerForRepaint(); 331 m_repaintRect = renderer()->clippedOverflowRectForRepaint(repaintContainer); 332 m_outlineBox = renderer()->outlineBoundsForRepaint(repaintContainer); 333 } 334 335 void RenderLayer::updateTransform() 336 { 337 // hasTransform() on the renderer is also true when there is transform-style: preserve-3d or perspective set, 338 // so check style too. 339 bool hasTransform = renderer()->hasTransform() && renderer()->style()->hasTransform(); 340 bool had3DTransform = has3DTransform(); 341 342 bool hadTransform = m_transform; 343 if (hasTransform != hadTransform) { 344 if (hasTransform) 345 m_transform.set(new TransformationMatrix); 346 else 347 m_transform.clear(); 348 } 349 350 if (hasTransform) { 351 RenderBox* box = renderBox(); 352 ASSERT(box); 353 m_transform->makeIdentity(); 354 box->style()->applyTransform(*m_transform, box->borderBoxRect().size(), RenderStyle::IncludeTransformOrigin); 355 makeMatrixRenderable(*m_transform, hasAcceleratedCompositing()); 356 } 357 358 if (had3DTransform != has3DTransform()) 359 dirty3DTransformedDescendantStatus(); 360 } 361 362 TransformationMatrix RenderLayer::currentTransform() const 363 { 364 if (!m_transform) 365 return TransformationMatrix(); 366 367 #if USE(ACCELERATED_COMPOSITING) 368 if (renderer()->style()->isRunningAcceleratedAnimation()) { 369 TransformationMatrix currTransform; 370 RefPtr<RenderStyle> style = renderer()->animation()->getAnimatedStyleForRenderer(renderer()); 371 style->applyTransform(currTransform, renderBox()->borderBoxRect().size(), RenderStyle::IncludeTransformOrigin); 372 makeMatrixRenderable(currTransform, hasAcceleratedCompositing()); 373 return currTransform; 374 } 375 #endif 376 377 return *m_transform; 378 } 379 380 TransformationMatrix RenderLayer::renderableTransform(PaintBehavior paintBehavior) const 381 { 382 if (!m_transform) 383 return TransformationMatrix(); 384 385 if (paintBehavior & PaintBehaviorFlattenCompositingLayers) { 386 TransformationMatrix matrix = *m_transform; 387 makeMatrixRenderable(matrix, false /* flatten 3d */); 388 return matrix; 389 } 390 391 return *m_transform; 392 } 393 394 void RenderLayer::setHasVisibleContent(bool b) 395 { 396 if (m_hasVisibleContent == b && !m_visibleContentStatusDirty) 397 return; 398 m_visibleContentStatusDirty = false; 399 m_hasVisibleContent = b; 400 if (m_hasVisibleContent) { 401 RenderBoxModelObject* repaintContainer = renderer()->containerForRepaint(); 402 m_repaintRect = renderer()->clippedOverflowRectForRepaint(repaintContainer); 403 m_outlineBox = renderer()->outlineBoundsForRepaint(repaintContainer); 404 if (!isNormalFlowOnly()) 405 dirtyStackingContextZOrderLists(); 406 } 407 if (parent()) 408 parent()->childVisibilityChanged(m_hasVisibleContent); 409 } 410 411 void RenderLayer::dirtyVisibleContentStatus() 412 { 413 m_visibleContentStatusDirty = true; 414 if (parent()) 415 parent()->dirtyVisibleDescendantStatus(); 416 } 417 418 void RenderLayer::childVisibilityChanged(bool newVisibility) 419 { 420 if (m_hasVisibleDescendant == newVisibility || m_visibleDescendantStatusDirty) 421 return; 422 if (newVisibility) { 423 RenderLayer* l = this; 424 while (l && !l->m_visibleDescendantStatusDirty && !l->m_hasVisibleDescendant) { 425 l->m_hasVisibleDescendant = true; 426 l = l->parent(); 427 } 428 } else 429 dirtyVisibleDescendantStatus(); 430 } 431 432 void RenderLayer::dirtyVisibleDescendantStatus() 433 { 434 RenderLayer* l = this; 435 while (l && !l->m_visibleDescendantStatusDirty) { 436 l->m_visibleDescendantStatusDirty = true; 437 l = l->parent(); 438 } 439 } 440 441 void RenderLayer::updateVisibilityStatus() 442 { 443 if (m_visibleDescendantStatusDirty) { 444 m_hasVisibleDescendant = false; 445 for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) { 446 child->updateVisibilityStatus(); 447 if (child->m_hasVisibleContent || child->m_hasVisibleDescendant) { 448 m_hasVisibleDescendant = true; 449 break; 450 } 451 } 452 m_visibleDescendantStatusDirty = false; 453 } 454 455 if (m_visibleContentStatusDirty) { 456 if (renderer()->style()->visibility() == VISIBLE) 457 m_hasVisibleContent = true; 458 else { 459 // layer may be hidden but still have some visible content, check for this 460 m_hasVisibleContent = false; 461 RenderObject* r = renderer()->firstChild(); 462 while (r) { 463 if (r->style()->visibility() == VISIBLE && !r->hasLayer()) { 464 m_hasVisibleContent = true; 465 break; 466 } 467 if (r->firstChild() && !r->hasLayer()) 468 r = r->firstChild(); 469 else if (r->nextSibling()) 470 r = r->nextSibling(); 471 else { 472 do { 473 r = r->parent(); 474 if (r == renderer()) 475 r = 0; 476 } while (r && !r->nextSibling()); 477 if (r) 478 r = r->nextSibling(); 479 } 480 } 481 } 482 m_visibleContentStatusDirty = false; 483 } 484 } 485 486 void RenderLayer::dirty3DTransformedDescendantStatus() 487 { 488 RenderLayer* curr = stackingContext(); 489 if (curr) 490 curr->m_3DTransformedDescendantStatusDirty = true; 491 492 // This propagates up through preserve-3d hierarchies to the enclosing flattening layer. 493 // Note that preserves3D() creates stacking context, so we can just run up the stacking contexts. 494 while (curr && curr->preserves3D()) { 495 curr->m_3DTransformedDescendantStatusDirty = true; 496 curr = curr->stackingContext(); 497 } 498 } 499 500 // Return true if this layer or any preserve-3d descendants have 3d. 501 bool RenderLayer::update3DTransformedDescendantStatus() 502 { 503 if (m_3DTransformedDescendantStatusDirty) { 504 m_has3DTransformedDescendant = false; 505 506 // Transformed or preserve-3d descendants can only be in the z-order lists, not 507 // in the normal flow list, so we only need to check those. 508 if (m_posZOrderList) { 509 for (unsigned i = 0; i < m_posZOrderList->size(); ++i) 510 m_has3DTransformedDescendant |= m_posZOrderList->at(i)->update3DTransformedDescendantStatus(); 511 } 512 513 // Now check our negative z-index children. 514 if (m_negZOrderList) { 515 for (unsigned i = 0; i < m_negZOrderList->size(); ++i) 516 m_has3DTransformedDescendant |= m_negZOrderList->at(i)->update3DTransformedDescendantStatus(); 517 } 518 519 m_3DTransformedDescendantStatusDirty = false; 520 } 521 522 // If we live in a 3d hierarchy, then the layer at the root of that hierarchy needs 523 // the m_has3DTransformedDescendant set. 524 if (preserves3D()) 525 return has3DTransform() || m_has3DTransformedDescendant; 526 527 return has3DTransform(); 528 } 529 530 void RenderLayer::updateLayerPosition() 531 { 532 // Clear our cached clip rect information. 533 clearClipRects(); 534 535 RenderBox* rendererBox = renderBox(); 536 537 int x = rendererBox ? rendererBox->x() : 0; 538 int y = rendererBox ? rendererBox->y() : 0; 539 540 if (!renderer()->isPositioned() && renderer()->parent()) { 541 // We must adjust our position by walking up the render tree looking for the 542 // nearest enclosing object with a layer. 543 RenderObject* curr = renderer()->parent(); 544 while (curr && !curr->hasLayer()) { 545 if (curr->isBox() && !curr->isTableRow()) { 546 // Rows and cells share the same coordinate space (that of the section). 547 // Omit them when computing our xpos/ypos. 548 RenderBox* currBox = toRenderBox(curr); 549 x += currBox->x(); 550 y += currBox->y(); 551 } 552 curr = curr->parent(); 553 } 554 if (curr->isBox() && curr->isTableRow()) { 555 // Put ourselves into the row coordinate space. 556 RenderBox* currBox = toRenderBox(curr); 557 x -= currBox->x(); 558 y -= currBox->y(); 559 } 560 } 561 562 m_relX = m_relY = 0; 563 if (renderer()->isRelPositioned()) { 564 m_relX = renderer()->relativePositionOffsetX(); 565 m_relY = renderer()->relativePositionOffsetY(); 566 x += m_relX; y += m_relY; 567 } 568 569 // Subtract our parent's scroll offset. 570 if (renderer()->isPositioned() && enclosingPositionedAncestor()) { 571 RenderLayer* positionedParent = enclosingPositionedAncestor(); 572 573 // For positioned layers, we subtract out the enclosing positioned layer's scroll offset. 574 positionedParent->subtractScrolledContentOffset(x, y); 575 576 if (renderer()->isPositioned() && positionedParent->renderer()->isRelPositioned() && positionedParent->renderer()->isRenderInline()) { 577 IntSize offset = toRenderInline(positionedParent->renderer())->relativePositionedInlineOffset(toRenderBox(renderer())); 578 x += offset.width(); 579 y += offset.height(); 580 } 581 } else if (parent()) 582 parent()->subtractScrolledContentOffset(x, y); 583 584 // FIXME: We'd really like to just get rid of the concept of a layer rectangle and rely on the renderers. 585 586 setLocation(x, y); 587 588 if (renderer()->isRenderInline()) { 589 RenderInline* inlineFlow = toRenderInline(renderer()); 590 IntRect lineBox = inlineFlow->linesBoundingBox(); 591 setWidth(lineBox.width()); 592 setHeight(lineBox.height()); 593 } else if (RenderBox* box = renderBox()) { 594 setWidth(box->width()); 595 setHeight(box->height()); 596 597 if (!box->hasOverflowClip()) { 598 if (box->rightLayoutOverflow() > box->width()) 599 setWidth(box->rightLayoutOverflow()); 600 if (box->bottomLayoutOverflow() > box->height()) 601 setHeight(box->bottomLayoutOverflow()); 602 } 603 } 604 } 605 606 TransformationMatrix RenderLayer::perspectiveTransform() const 607 { 608 if (!renderer()->hasTransform()) 609 return TransformationMatrix(); 610 611 RenderStyle* style = renderer()->style(); 612 if (!style->hasPerspective()) 613 return TransformationMatrix(); 614 615 // Maybe fetch the perspective from the backing? 616 const IntRect borderBox = toRenderBox(renderer())->borderBoxRect(); 617 const float boxWidth = borderBox.width(); 618 const float boxHeight = borderBox.height(); 619 620 float perspectiveOriginX = style->perspectiveOriginX().calcFloatValue(boxWidth); 621 float perspectiveOriginY = style->perspectiveOriginY().calcFloatValue(boxHeight); 622 623 // A perspective origin of 0,0 makes the vanishing point in the center of the element. 624 // We want it to be in the top-left, so subtract half the height and width. 625 perspectiveOriginX -= boxWidth / 2.0f; 626 perspectiveOriginY -= boxHeight / 2.0f; 627 628 TransformationMatrix t; 629 t.translate(perspectiveOriginX, perspectiveOriginY); 630 t.applyPerspective(style->perspective()); 631 t.translate(-perspectiveOriginX, -perspectiveOriginY); 632 633 return t; 634 } 635 636 FloatPoint RenderLayer::perspectiveOrigin() const 637 { 638 if (!renderer()->hasTransform()) 639 return FloatPoint(); 640 641 const IntRect borderBox = toRenderBox(renderer())->borderBoxRect(); 642 RenderStyle* style = renderer()->style(); 643 644 return FloatPoint(style->perspectiveOriginX().calcFloatValue(borderBox.width()), 645 style->perspectiveOriginY().calcFloatValue(borderBox.height())); 646 } 647 648 RenderLayer* RenderLayer::stackingContext() const 649 { 650 RenderLayer* layer = parent(); 651 #if ENABLE(COMPOSITED_FIXED_ELEMENTS) 652 // When using composited fixed elements, they are turned into a stacking 653 // context and we thus need to return them. 654 // We can simplify the while loop by using isStackingContext(); with 655 // composited fixed elements turned on, this will return true for them, 656 // and is otherwise equivalent to the replaced statements. 657 while (layer && !layer->renderer()->isRoot() && !layer->isStackingContext()) 658 #else 659 while (layer && !layer->renderer()->isRenderView() && !layer->renderer()->isRoot() && layer->renderer()->style()->hasAutoZIndex()) 660 #endif 661 layer = layer->parent(); 662 return layer; 663 } 664 665 static inline bool isPositionedContainer(RenderLayer* layer) 666 { 667 RenderObject* o = layer->renderer(); 668 return o->isRenderView() || o->isPositioned() || o->isRelPositioned() || layer->hasTransform(); 669 } 670 671 static inline bool isFixedPositionedContainer(RenderLayer* layer) 672 { 673 RenderObject* o = layer->renderer(); 674 return o->isRenderView() || layer->hasTransform(); 675 } 676 677 RenderLayer* RenderLayer::enclosingPositionedAncestor() const 678 { 679 RenderLayer* curr = parent(); 680 while (curr && !isPositionedContainer(curr)) 681 curr = curr->parent(); 682 683 return curr; 684 } 685 686 RenderLayer* RenderLayer::enclosingTransformedAncestor() const 687 { 688 RenderLayer* curr = parent(); 689 while (curr && !curr->renderer()->isRenderView() && !curr->transform()) 690 curr = curr->parent(); 691 692 return curr; 693 } 694 695 static inline const RenderLayer* compositingContainer(const RenderLayer* layer) 696 { 697 return layer->isNormalFlowOnly() ? layer->parent() : layer->stackingContext(); 698 } 699 700 #if USE(ACCELERATED_COMPOSITING) 701 RenderLayer* RenderLayer::enclosingCompositingLayer(bool includeSelf) const 702 { 703 if (includeSelf && isComposited()) 704 return const_cast<RenderLayer*>(this); 705 706 for (const RenderLayer* curr = compositingContainer(this); curr; curr = compositingContainer(curr)) { 707 if (curr->isComposited()) 708 return const_cast<RenderLayer*>(curr); 709 } 710 711 return 0; 712 } 713 #endif 714 715 RenderLayer* RenderLayer::clippingRoot() const 716 { 717 const RenderLayer* current = this; 718 while (current) { 719 if (current->renderer()->isRenderView()) 720 return const_cast<RenderLayer*>(current); 721 722 current = compositingContainer(current); 723 ASSERT(current); 724 if (current->transform() 725 #if USE(ACCELERATED_COMPOSITING) 726 || current->isComposited() 727 #endif 728 ) 729 return const_cast<RenderLayer*>(current); 730 } 731 732 ASSERT_NOT_REACHED(); 733 return 0; 734 } 735 736 IntPoint RenderLayer::absoluteToContents(const IntPoint& absolutePoint) const 737 { 738 // We don't use convertToLayerCoords because it doesn't know about transforms 739 return roundedIntPoint(renderer()->absoluteToLocal(absolutePoint, false, true)); 740 } 741 742 bool RenderLayer::requiresSlowRepaints() const 743 { 744 if (isTransparent() || hasReflection() || hasTransform()) 745 return true; 746 if (!parent()) 747 return false; 748 return parent()->requiresSlowRepaints(); 749 } 750 751 bool RenderLayer::isTransparent() const 752 { 753 #if ENABLE(SVG) 754 if (renderer()->node() && renderer()->node()->namespaceURI() == SVGNames::svgNamespaceURI) 755 return false; 756 #endif 757 return renderer()->isTransparent() || renderer()->hasMask(); 758 } 759 760 RenderLayer* RenderLayer::transparentPaintingAncestor() 761 { 762 if (isComposited()) 763 return 0; 764 765 for (RenderLayer* curr = parent(); curr; curr = curr->parent()) { 766 if (curr->isComposited()) 767 return 0; 768 if (curr->isTransparent()) 769 return curr; 770 } 771 return 0; 772 } 773 774 static IntRect transparencyClipBox(const RenderLayer* l, const RenderLayer* rootLayer, PaintBehavior paintBehavior); 775 776 static void expandClipRectForDescendantsAndReflection(IntRect& clipRect, const RenderLayer* l, const RenderLayer* rootLayer, PaintBehavior paintBehavior) 777 { 778 // If we have a mask, then the clip is limited to the border box area (and there is 779 // no need to examine child layers). 780 if (!l->renderer()->hasMask()) { 781 // Note: we don't have to walk z-order lists since transparent elements always establish 782 // a stacking context. This means we can just walk the layer tree directly. 783 for (RenderLayer* curr = l->firstChild(); curr; curr = curr->nextSibling()) { 784 if (!l->reflection() || l->reflectionLayer() != curr) 785 clipRect.unite(transparencyClipBox(curr, rootLayer, paintBehavior)); 786 } 787 } 788 789 // If we have a reflection, then we need to account for that when we push the clip. Reflect our entire 790 // current transparencyClipBox to catch all child layers. 791 // FIXME: Accelerated compositing will eventually want to do something smart here to avoid incorporating this 792 // size into the parent layer. 793 if (l->renderer()->hasReflection()) { 794 int deltaX = 0; 795 int deltaY = 0; 796 l->convertToLayerCoords(rootLayer, deltaX, deltaY); 797 clipRect.move(-deltaX, -deltaY); 798 clipRect.unite(l->renderBox()->reflectedRect(clipRect)); 799 clipRect.move(deltaX, deltaY); 800 } 801 } 802 803 static IntRect transparencyClipBox(const RenderLayer* l, const RenderLayer* rootLayer, PaintBehavior paintBehavior) 804 { 805 // FIXME: Although this function completely ignores CSS-imposed clipping, we did already intersect with the 806 // paintDirtyRect, and that should cut down on the amount we have to paint. Still it 807 // would be better to respect clips. 808 809 if (rootLayer != l && l->paintsWithTransform(paintBehavior)) { 810 // The best we can do here is to use enclosed bounding boxes to establish a "fuzzy" enough clip to encompass 811 // the transformed layer and all of its children. 812 int x = 0; 813 int y = 0; 814 l->convertToLayerCoords(rootLayer, x, y); 815 816 TransformationMatrix transform; 817 transform.translate(x, y); 818 transform = *l->transform() * transform; 819 820 IntRect clipRect = l->boundingBox(l); 821 expandClipRectForDescendantsAndReflection(clipRect, l, l, paintBehavior); 822 return transform.mapRect(clipRect); 823 } 824 825 IntRect clipRect = l->boundingBox(rootLayer); 826 expandClipRectForDescendantsAndReflection(clipRect, l, rootLayer, paintBehavior); 827 return clipRect; 828 } 829 830 void RenderLayer::beginTransparencyLayers(GraphicsContext* p, const RenderLayer* rootLayer, PaintBehavior paintBehavior) 831 { 832 if (p->paintingDisabled() || (paintsWithTransparency(paintBehavior) && m_usedTransparency)) 833 return; 834 835 RenderLayer* ancestor = transparentPaintingAncestor(); 836 if (ancestor) 837 ancestor->beginTransparencyLayers(p, rootLayer, paintBehavior); 838 839 if (paintsWithTransparency(paintBehavior)) { 840 m_usedTransparency = true; 841 p->save(); 842 IntRect clipRect = transparencyClipBox(this, rootLayer, paintBehavior); 843 p->clip(clipRect); 844 p->beginTransparencyLayer(renderer()->opacity()); 845 #ifdef REVEAL_TRANSPARENCY_LAYERS 846 p->setFillColor(Color(0.0f, 0.0f, 0.5f, 0.2f), DeviceColorSpace); 847 p->fillRect(clipRect); 848 #endif 849 } 850 } 851 852 void* RenderLayer::operator new(size_t sz, RenderArena* renderArena) throw() 853 { 854 return renderArena->allocate(sz); 855 } 856 857 void RenderLayer::operator delete(void* ptr, size_t sz) 858 { 859 // Stash size where destroy can find it. 860 *(size_t *)ptr = sz; 861 } 862 863 void RenderLayer::destroy(RenderArena* renderArena) 864 { 865 delete this; 866 867 // Recover the size left there for us by operator delete and free the memory. 868 renderArena->free(*(size_t *)this, this); 869 } 870 871 void RenderLayer::addChild(RenderLayer* child, RenderLayer* beforeChild) 872 { 873 RenderLayer* prevSibling = beforeChild ? beforeChild->previousSibling() : lastChild(); 874 if (prevSibling) { 875 child->setPreviousSibling(prevSibling); 876 prevSibling->setNextSibling(child); 877 } else 878 setFirstChild(child); 879 880 if (beforeChild) { 881 beforeChild->setPreviousSibling(child); 882 child->setNextSibling(beforeChild); 883 } else 884 setLastChild(child); 885 886 child->setParent(this); 887 888 if (child->isNormalFlowOnly()) 889 dirtyNormalFlowList(); 890 891 if (!child->isNormalFlowOnly() || child->firstChild()) { 892 // Dirty the z-order list in which we are contained. The stackingContext() can be null in the 893 // case where we're building up generated content layers. This is ok, since the lists will start 894 // off dirty in that case anyway. 895 child->dirtyStackingContextZOrderLists(); 896 } 897 898 child->updateVisibilityStatus(); 899 if (child->m_hasVisibleContent || child->m_hasVisibleDescendant) 900 childVisibilityChanged(true); 901 902 #if USE(ACCELERATED_COMPOSITING) 903 compositor()->layerWasAdded(this, child); 904 #endif 905 } 906 907 RenderLayer* RenderLayer::removeChild(RenderLayer* oldChild) 908 { 909 #if USE(ACCELERATED_COMPOSITING) 910 if (!renderer()->documentBeingDestroyed()) 911 compositor()->layerWillBeRemoved(this, oldChild); 912 #endif 913 914 // remove the child 915 if (oldChild->previousSibling()) 916 oldChild->previousSibling()->setNextSibling(oldChild->nextSibling()); 917 if (oldChild->nextSibling()) 918 oldChild->nextSibling()->setPreviousSibling(oldChild->previousSibling()); 919 920 if (m_first == oldChild) 921 m_first = oldChild->nextSibling(); 922 if (m_last == oldChild) 923 m_last = oldChild->previousSibling(); 924 925 if (oldChild->isNormalFlowOnly()) 926 dirtyNormalFlowList(); 927 if (!oldChild->isNormalFlowOnly() || oldChild->firstChild()) { 928 // Dirty the z-order list in which we are contained. When called via the 929 // reattachment process in removeOnlyThisLayer, the layer may already be disconnected 930 // from the main layer tree, so we need to null-check the |stackingContext| value. 931 oldChild->dirtyStackingContextZOrderLists(); 932 } 933 934 oldChild->setPreviousSibling(0); 935 oldChild->setNextSibling(0); 936 oldChild->setParent(0); 937 938 oldChild->updateVisibilityStatus(); 939 if (oldChild->m_hasVisibleContent || oldChild->m_hasVisibleDescendant) 940 childVisibilityChanged(false); 941 942 return oldChild; 943 } 944 945 void RenderLayer::removeOnlyThisLayer() 946 { 947 if (!m_parent) 948 return; 949 950 // Mark that we are about to lose our layer. This makes render tree 951 // walks ignore this layer while we're removing it. 952 m_renderer->setHasLayer(false); 953 954 #if USE(ACCELERATED_COMPOSITING) 955 compositor()->layerWillBeRemoved(m_parent, this); 956 #endif 957 958 // Dirty the clip rects. 959 clearClipRectsIncludingDescendants(); 960 961 // Remove us from the parent. 962 RenderLayer* parent = m_parent; 963 RenderLayer* nextSib = nextSibling(); 964 parent->removeChild(this); 965 966 if (reflection()) 967 removeChild(reflectionLayer()); 968 969 // Now walk our kids and reattach them to our parent. 970 RenderLayer* current = m_first; 971 while (current) { 972 RenderLayer* next = current->nextSibling(); 973 removeChild(current); 974 parent->addChild(current, nextSib); 975 current->updateLayerPositions(); // Depends on hasLayer() already being false for proper layout. 976 current = next; 977 } 978 979 m_renderer->destroyLayer(); 980 } 981 982 void RenderLayer::insertOnlyThisLayer() 983 { 984 if (!m_parent && renderer()->parent()) { 985 // We need to connect ourselves when our renderer() has a parent. 986 // Find our enclosingLayer and add ourselves. 987 RenderLayer* parentLayer = renderer()->parent()->enclosingLayer(); 988 ASSERT(parentLayer); 989 RenderLayer* beforeChild = parentLayer->reflectionLayer() != this ? renderer()->parent()->findNextLayer(parentLayer, renderer()) : 0; 990 parentLayer->addChild(this, beforeChild); 991 } 992 993 // Remove all descendant layers from the hierarchy and add them to the new position. 994 for (RenderObject* curr = renderer()->firstChild(); curr; curr = curr->nextSibling()) 995 curr->moveLayers(m_parent, this); 996 997 // Clear out all the clip rects. 998 clearClipRectsIncludingDescendants(); 999 } 1000 1001 void 1002 RenderLayer::convertToLayerCoords(const RenderLayer* ancestorLayer, int& xPos, int& yPos) const 1003 { 1004 if (ancestorLayer == this) 1005 return; 1006 1007 EPosition position = renderer()->style()->position(); 1008 if (position == FixedPosition && (!ancestorLayer || ancestorLayer == renderer()->view()->layer())) { 1009 // If the fixed layer's container is the root, just add in the offset of the view. We can obtain this by calling 1010 // localToAbsolute() on the RenderView. 1011 FloatPoint absPos = renderer()->localToAbsolute(FloatPoint(), true); 1012 xPos += absPos.x(); 1013 yPos += absPos.y(); 1014 return; 1015 } 1016 1017 if (position == FixedPosition) { 1018 // For a fixed layers, we need to walk up to the root to see if there's a fixed position container 1019 // (e.g. a transformed layer). It's an error to call convertToLayerCoords() across a layer with a transform, 1020 // so we should always find the ancestor at or before we find the fixed position container. 1021 RenderLayer* fixedPositionContainerLayer = 0; 1022 bool foundAncestor = false; 1023 for (RenderLayer* currLayer = parent(); currLayer; currLayer = currLayer->parent()) { 1024 if (currLayer == ancestorLayer) 1025 foundAncestor = true; 1026 1027 if (isFixedPositionedContainer(currLayer)) { 1028 fixedPositionContainerLayer = currLayer; 1029 ASSERT(foundAncestor); 1030 break; 1031 } 1032 } 1033 1034 ASSERT(fixedPositionContainerLayer); // We should have hit the RenderView's layer at least. 1035 1036 if (fixedPositionContainerLayer != ancestorLayer) { 1037 int fixedContainerX = 0; 1038 int fixedContainerY = 0; 1039 convertToLayerCoords(fixedPositionContainerLayer, fixedContainerX, fixedContainerY); 1040 1041 int ancestorX = 0; 1042 int ancestorY = 0; 1043 ancestorLayer->convertToLayerCoords(fixedPositionContainerLayer, ancestorX, ancestorY); 1044 1045 xPos += (fixedContainerX - ancestorX); 1046 yPos += (fixedContainerY - ancestorY); 1047 return; 1048 } 1049 } 1050 1051 1052 RenderLayer* parentLayer; 1053 if (position == AbsolutePosition || position == FixedPosition) { 1054 // Do what enclosingPositionedAncestor() does, but check for ancestorLayer along the way. 1055 parentLayer = parent(); 1056 bool foundAncestorFirst = false; 1057 while (parentLayer) { 1058 if (isPositionedContainer(parentLayer)) 1059 break; 1060 1061 if (parentLayer == ancestorLayer) { 1062 foundAncestorFirst = true; 1063 break; 1064 } 1065 1066 parentLayer = parentLayer->parent(); 1067 } 1068 1069 if (foundAncestorFirst) { 1070 // Found ancestorLayer before the abs. positioned container, so compute offset of both relative 1071 // to enclosingPositionedAncestor and subtract. 1072 RenderLayer* positionedAncestor = parentLayer->enclosingPositionedAncestor(); 1073 1074 int thisX = 0; 1075 int thisY = 0; 1076 convertToLayerCoords(positionedAncestor, thisX, thisY); 1077 1078 int ancestorX = 0; 1079 int ancestorY = 0; 1080 ancestorLayer->convertToLayerCoords(positionedAncestor, ancestorX, ancestorY); 1081 1082 xPos += (thisX - ancestorX); 1083 yPos += (thisY - ancestorY); 1084 return; 1085 } 1086 } else 1087 parentLayer = parent(); 1088 1089 if (!parentLayer) 1090 return; 1091 1092 parentLayer->convertToLayerCoords(ancestorLayer, xPos, yPos); 1093 1094 xPos += x(); 1095 yPos += y(); 1096 } 1097 1098 static inline int adjustedScrollDelta(int beginningDelta) { 1099 // This implemention matches Firefox's. 1100 // http://mxr.mozilla.org/firefox/source/toolkit/content/widgets/browser.xml#856. 1101 const int speedReducer = 12; 1102 1103 int adjustedDelta = beginningDelta / speedReducer; 1104 if (adjustedDelta > 1) 1105 adjustedDelta = static_cast<int>(adjustedDelta * sqrt(static_cast<double>(adjustedDelta))) - 1; 1106 else if (adjustedDelta < -1) 1107 adjustedDelta = static_cast<int>(adjustedDelta * sqrt(static_cast<double>(-adjustedDelta))) + 1; 1108 1109 return adjustedDelta; 1110 } 1111 1112 void RenderLayer::panScrollFromPoint(const IntPoint& sourcePoint) 1113 { 1114 Frame* frame = renderer()->document()->frame(); 1115 if (!frame) 1116 return; 1117 1118 IntPoint currentMousePosition = frame->eventHandler()->currentMousePosition(); 1119 1120 // We need to check if the current mouse position is out of the window. When the mouse is out of the window, the position is incoherent 1121 static IntPoint previousMousePosition; 1122 if (currentMousePosition.x() < 0 || currentMousePosition.y() < 0) 1123 currentMousePosition = previousMousePosition; 1124 else 1125 previousMousePosition = currentMousePosition; 1126 1127 int xDelta = currentMousePosition.x() - sourcePoint.x(); 1128 int yDelta = currentMousePosition.y() - sourcePoint.y(); 1129 1130 if (abs(xDelta) <= ScrollView::noPanScrollRadius) // at the center we let the space for the icon 1131 xDelta = 0; 1132 if (abs(yDelta) <= ScrollView::noPanScrollRadius) 1133 yDelta = 0; 1134 1135 scrollByRecursively(adjustedScrollDelta(xDelta), adjustedScrollDelta(yDelta)); 1136 } 1137 1138 void RenderLayer::scrollByRecursively(int xDelta, int yDelta) 1139 { 1140 if (!xDelta && !yDelta) 1141 return; 1142 1143 bool restrictedByLineClamp = false; 1144 if (renderer()->parent()) 1145 restrictedByLineClamp = !renderer()->parent()->style()->lineClamp().isNone(); 1146 1147 if (renderer()->hasOverflowClip() && !restrictedByLineClamp) { 1148 int newOffsetX = scrollXOffset() + xDelta; 1149 int newOffsetY = scrollYOffset() + yDelta; 1150 scrollToOffset(newOffsetX, newOffsetY); 1151 1152 // If this layer can't do the scroll we ask the next layer up that can scroll to try 1153 int leftToScrollX = newOffsetX - scrollXOffset(); 1154 int leftToScrollY = newOffsetY - scrollYOffset(); 1155 if ((leftToScrollX || leftToScrollY) && renderer()->parent()) { 1156 RenderObject* nextRenderer = renderer()->parent(); 1157 while (nextRenderer) { 1158 if (nextRenderer->isBox() && toRenderBox(nextRenderer)->canBeScrolledAndHasScrollableArea()) { 1159 nextRenderer->enclosingLayer()->scrollByRecursively(leftToScrollX, leftToScrollY); 1160 break; 1161 } 1162 nextRenderer = nextRenderer->parent(); 1163 } 1164 1165 Frame* frame = renderer()->document()->frame(); 1166 if (frame) 1167 frame->eventHandler()->updateAutoscrollRenderer(); 1168 } 1169 } else if (renderer()->view()->frameView()) { 1170 // If we are here, we were called on a renderer that can be programmatically scrolled, but doesn't 1171 // have an overflow clip. Which means that it is a document node that can be scrolled. 1172 renderer()->view()->frameView()->scrollBy(IntSize(xDelta, yDelta)); 1173 // FIXME: If we didn't scroll the whole way, do we want to try looking at the frames ownerElement? 1174 // https://bugs.webkit.org/show_bug.cgi?id=28237 1175 } 1176 } 1177 1178 1179 void 1180 RenderLayer::addScrolledContentOffset(int& x, int& y) const 1181 { 1182 x += scrollXOffset() + m_scrollLeftOverflow; 1183 y += scrollYOffset(); 1184 } 1185 1186 void 1187 RenderLayer::subtractScrolledContentOffset(int& x, int& y) const 1188 { 1189 x -= scrollXOffset() + m_scrollLeftOverflow; 1190 y -= scrollYOffset(); 1191 } 1192 1193 void RenderLayer::scrollToOffset(int x, int y, bool updateScrollbars, bool repaint) 1194 { 1195 RenderBox* box = renderBox(); 1196 if (!box) 1197 return; 1198 1199 if (box->style()->overflowX() != OMARQUEE) { 1200 if (x < 0) x = 0; 1201 if (y < 0) y = 0; 1202 1203 // Call the scrollWidth/Height functions so that the dimensions will be computed if they need 1204 // to be (for overflow:hidden blocks). 1205 int maxX = scrollWidth() - box->clientWidth(); 1206 int maxY = scrollHeight() - box->clientHeight(); 1207 1208 if (x > maxX) x = maxX; 1209 if (y > maxY) y = maxY; 1210 } 1211 1212 // FIXME: Eventually, we will want to perform a blit. For now never 1213 // blit, since the check for blitting is going to be very 1214 // complicated (since it will involve testing whether our layer 1215 // is either occluded by another layer or clipped by an enclosing 1216 // layer or contains fixed backgrounds, etc.). 1217 int newScrollX = x - m_scrollOriginX; 1218 if (m_scrollY == y && m_scrollX == newScrollX) 1219 return; 1220 m_scrollX = newScrollX; 1221 m_scrollY = y; 1222 1223 // Update the positions of our child layers. Don't have updateLayerPositions() update 1224 // compositing layers, because we need to do a deep update from the compositing ancestor. 1225 for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) 1226 child->updateLayerPositions(0); 1227 1228 #if USE(ACCELERATED_COMPOSITING) 1229 if (compositor()->inCompositingMode()) { 1230 if (RenderLayer* compositingAncestor = ancestorCompositingLayer()) { 1231 bool isUpdateRoot = true; 1232 compositingAncestor->backing()->updateAfterLayout(RenderLayerBacking::AllDescendants, isUpdateRoot); 1233 } 1234 } 1235 #endif 1236 1237 RenderView* view = renderer()->view(); 1238 1239 // We should have a RenderView if we're trying to scroll. 1240 ASSERT(view); 1241 if (view) { 1242 #if ENABLE(DASHBOARD_SUPPORT) 1243 // Update dashboard regions, scrolling may change the clip of a 1244 // particular region. 1245 view->frameView()->updateDashboardRegions(); 1246 #endif 1247 1248 view->updateWidgetPositions(); 1249 } 1250 1251 // The caret rect needs to be invalidated after scrolling 1252 Frame* frame = renderer()->document()->frame(); 1253 if (frame) 1254 frame->selection()->setNeedsLayout(); 1255 1256 // Just schedule a full repaint of our object. 1257 if (repaint) 1258 renderer()->repaint(); 1259 1260 if (updateScrollbars) { 1261 if (m_hBar) 1262 m_hBar->setValue(scrollXOffset()); 1263 if (m_vBar) 1264 m_vBar->setValue(m_scrollY); 1265 } 1266 1267 // Schedule the scroll DOM event. 1268 if (view) { 1269 if (FrameView* frameView = view->frameView()) 1270 frameView->scheduleEvent(Event::create(eventNames().scrollEvent, false, false), renderer()->node()); 1271 } 1272 } 1273 1274 void RenderLayer::scrollRectToVisible(const IntRect &rect, bool scrollToAnchor, const ScrollAlignment& alignX, const ScrollAlignment& alignY) 1275 { 1276 RenderLayer* parentLayer = 0; 1277 IntRect newRect = rect; 1278 int xOffset = 0, yOffset = 0; 1279 1280 // We may end up propagating a scroll event. It is important that we suspend events until 1281 // the end of the function since they could delete the layer or the layer's renderer(). 1282 FrameView* frameView = renderer()->document()->view(); 1283 if (frameView) 1284 frameView->pauseScheduledEvents(); 1285 1286 bool restrictedByLineClamp = false; 1287 if (renderer()->parent()) { 1288 parentLayer = renderer()->parent()->enclosingLayer(); 1289 restrictedByLineClamp = !renderer()->parent()->style()->lineClamp().isNone(); 1290 } 1291 1292 if (renderer()->hasOverflowClip() && !restrictedByLineClamp) { 1293 // Don't scroll to reveal an overflow layer that is restricted by the -webkit-line-clamp property. 1294 // This will prevent us from revealing text hidden by the slider in Safari RSS. 1295 RenderBox* box = renderBox(); 1296 ASSERT(box); 1297 FloatPoint absPos = box->localToAbsolute(); 1298 absPos.move(box->borderLeft(), box->borderTop()); 1299 1300 IntRect layerBounds = IntRect(absPos.x() + scrollXOffset(), absPos.y() + scrollYOffset(), box->clientWidth(), box->clientHeight()); 1301 IntRect exposeRect = IntRect(rect.x() + scrollXOffset(), rect.y() + scrollYOffset(), rect.width(), rect.height()); 1302 IntRect r = getRectToExpose(layerBounds, exposeRect, alignX, alignY); 1303 1304 xOffset = r.x() - absPos.x(); 1305 yOffset = r.y() - absPos.y(); 1306 // Adjust offsets if they're outside of the allowable range. 1307 xOffset = max(0, min(scrollWidth() - layerBounds.width(), xOffset)); 1308 yOffset = max(0, min(scrollHeight() - layerBounds.height(), yOffset)); 1309 1310 if (xOffset != scrollXOffset() || yOffset != scrollYOffset()) { 1311 int diffX = scrollXOffset(); 1312 int diffY = scrollYOffset(); 1313 scrollToOffset(xOffset, yOffset); 1314 diffX = scrollXOffset() - diffX; 1315 diffY = scrollYOffset() - diffY; 1316 newRect.setX(rect.x() - diffX); 1317 newRect.setY(rect.y() - diffY); 1318 } 1319 } else if (!parentLayer && renderer()->isBox() && renderBox()->canBeProgramaticallyScrolled(scrollToAnchor)) { 1320 if (frameView) { 1321 if (renderer()->document() && renderer()->document()->ownerElement() && renderer()->document()->ownerElement()->renderer()) { 1322 IntRect viewRect = frameView->visibleContentRect(); 1323 IntRect r = getRectToExpose(viewRect, rect, alignX, alignY); 1324 1325 xOffset = r.x(); 1326 yOffset = r.y(); 1327 // Adjust offsets if they're outside of the allowable range. 1328 xOffset = max(0, min(frameView->contentsWidth(), xOffset)); 1329 yOffset = max(0, min(frameView->contentsHeight(), yOffset)); 1330 1331 frameView->setScrollPosition(IntPoint(xOffset, yOffset)); 1332 parentLayer = renderer()->document()->ownerElement()->renderer()->enclosingLayer(); 1333 newRect.setX(rect.x() - frameView->scrollX() + frameView->x()); 1334 newRect.setY(rect.y() - frameView->scrollY() + frameView->y()); 1335 } else { 1336 IntRect viewRect = frameView->visibleContentRect(true); 1337 IntRect r = getRectToExpose(viewRect, rect, alignX, alignY); 1338 1339 // If this is the outermost view that RenderLayer needs to scroll, then we should scroll the view recursively 1340 // Other apps, like Mail, rely on this feature. 1341 frameView->scrollRectIntoViewRecursively(r); 1342 } 1343 } 1344 } 1345 1346 if (parentLayer) 1347 parentLayer->scrollRectToVisible(newRect, scrollToAnchor, alignX, alignY); 1348 1349 if (frameView) 1350 frameView->resumeScheduledEvents(); 1351 } 1352 1353 IntRect RenderLayer::getRectToExpose(const IntRect &visibleRect, const IntRect &exposeRect, const ScrollAlignment& alignX, const ScrollAlignment& alignY) 1354 { 1355 // Determine the appropriate X behavior. 1356 ScrollBehavior scrollX; 1357 IntRect exposeRectX(exposeRect.x(), visibleRect.y(), exposeRect.width(), visibleRect.height()); 1358 int intersectWidth = intersection(visibleRect, exposeRectX).width(); 1359 if (intersectWidth == exposeRect.width() || intersectWidth >= MIN_INTERSECT_FOR_REVEAL) 1360 // If the rectangle is fully visible, use the specified visible behavior. 1361 // If the rectangle is partially visible, but over a certain threshold, 1362 // then treat it as fully visible to avoid unnecessary horizontal scrolling 1363 scrollX = ScrollAlignment::getVisibleBehavior(alignX); 1364 else if (intersectWidth == visibleRect.width()) { 1365 // If the rect is bigger than the visible area, don't bother trying to center. Other alignments will work. 1366 scrollX = ScrollAlignment::getVisibleBehavior(alignX); 1367 if (scrollX == alignCenter) 1368 scrollX = noScroll; 1369 } else if (intersectWidth > 0) 1370 // If the rectangle is partially visible, but not above the minimum threshold, use the specified partial behavior 1371 scrollX = ScrollAlignment::getPartialBehavior(alignX); 1372 else 1373 scrollX = ScrollAlignment::getHiddenBehavior(alignX); 1374 // If we're trying to align to the closest edge, and the exposeRect is further right 1375 // than the visibleRect, and not bigger than the visible area, then align with the right. 1376 if (scrollX == alignToClosestEdge && exposeRect.right() > visibleRect.right() && exposeRect.width() < visibleRect.width()) 1377 scrollX = alignRight; 1378 1379 // Given the X behavior, compute the X coordinate. 1380 int x; 1381 if (scrollX == noScroll) 1382 x = visibleRect.x(); 1383 else if (scrollX == alignRight) 1384 x = exposeRect.right() - visibleRect.width(); 1385 else if (scrollX == alignCenter) 1386 x = exposeRect.x() + (exposeRect.width() - visibleRect.width()) / 2; 1387 else 1388 x = exposeRect.x(); 1389 1390 // Determine the appropriate Y behavior. 1391 ScrollBehavior scrollY; 1392 IntRect exposeRectY(visibleRect.x(), exposeRect.y(), visibleRect.width(), exposeRect.height()); 1393 int intersectHeight = intersection(visibleRect, exposeRectY).height(); 1394 if (intersectHeight == exposeRect.height()) 1395 // If the rectangle is fully visible, use the specified visible behavior. 1396 scrollY = ScrollAlignment::getVisibleBehavior(alignY); 1397 else if (intersectHeight == visibleRect.height()) { 1398 // If the rect is bigger than the visible area, don't bother trying to center. Other alignments will work. 1399 scrollY = ScrollAlignment::getVisibleBehavior(alignY); 1400 if (scrollY == alignCenter) 1401 scrollY = noScroll; 1402 } else if (intersectHeight > 0) 1403 // If the rectangle is partially visible, use the specified partial behavior 1404 scrollY = ScrollAlignment::getPartialBehavior(alignY); 1405 else 1406 scrollY = ScrollAlignment::getHiddenBehavior(alignY); 1407 // If we're trying to align to the closest edge, and the exposeRect is further down 1408 // than the visibleRect, and not bigger than the visible area, then align with the bottom. 1409 if (scrollY == alignToClosestEdge && exposeRect.bottom() > visibleRect.bottom() && exposeRect.height() < visibleRect.height()) 1410 scrollY = alignBottom; 1411 1412 // Given the Y behavior, compute the Y coordinate. 1413 int y; 1414 if (scrollY == noScroll) 1415 y = visibleRect.y(); 1416 else if (scrollY == alignBottom) 1417 y = exposeRect.bottom() - visibleRect.height(); 1418 else if (scrollY == alignCenter) 1419 y = exposeRect.y() + (exposeRect.height() - visibleRect.height()) / 2; 1420 else 1421 y = exposeRect.y(); 1422 1423 return IntRect(IntPoint(x, y), visibleRect.size()); 1424 } 1425 1426 void RenderLayer::autoscroll() 1427 { 1428 Frame* frame = renderer()->document()->frame(); 1429 if (!frame) 1430 return; 1431 1432 FrameView* frameView = frame->view(); 1433 if (!frameView) 1434 return; 1435 1436 #if ENABLE(DRAG_SUPPORT) 1437 frame->eventHandler()->updateSelectionForMouseDrag(); 1438 #endif 1439 1440 IntPoint currentDocumentPosition = frameView->windowToContents(frame->eventHandler()->currentMousePosition()); 1441 scrollRectToVisible(IntRect(currentDocumentPosition, IntSize(1, 1)), false, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignToEdgeIfNeeded); 1442 } 1443 1444 void RenderLayer::resize(const PlatformMouseEvent& evt, const IntSize& oldOffset) 1445 { 1446 // FIXME: This should be possible on generated content but is not right now. 1447 if (!inResizeMode() || !renderer()->hasOverflowClip() || !renderer()->node()) 1448 return; 1449 1450 // Set the width and height of the shadow ancestor node if there is one. 1451 // This is necessary for textarea elements since the resizable layer is in the shadow content. 1452 Element* element = static_cast<Element*>(renderer()->node()->shadowAncestorNode()); 1453 RenderBox* renderer = toRenderBox(element->renderer()); 1454 1455 EResize resize = renderer->style()->resize(); 1456 if (resize == RESIZE_NONE) 1457 return; 1458 1459 Document* document = element->document(); 1460 if (!document->frame()->eventHandler()->mousePressed()) 1461 return; 1462 1463 float zoomFactor = renderer->style()->effectiveZoom(); 1464 1465 IntSize newOffset = offsetFromResizeCorner(document->view()->windowToContents(evt.pos())); 1466 newOffset.setWidth(newOffset.width() / zoomFactor); 1467 newOffset.setHeight(newOffset.height() / zoomFactor); 1468 1469 IntSize currentSize = IntSize(renderer->width() / zoomFactor, renderer->height() / zoomFactor); 1470 IntSize minimumSize = element->minimumSizeForResizing().shrunkTo(currentSize); 1471 element->setMinimumSizeForResizing(minimumSize); 1472 1473 IntSize adjustedOldOffset = IntSize(oldOffset.width() / zoomFactor, oldOffset.height() / zoomFactor); 1474 1475 IntSize difference = (currentSize + newOffset - adjustedOldOffset).expandedTo(minimumSize) - currentSize; 1476 1477 CSSStyleDeclaration* style = element->style(); 1478 bool isBoxSizingBorder = renderer->style()->boxSizing() == BORDER_BOX; 1479 1480 ExceptionCode ec; 1481 1482 if (resize != RESIZE_VERTICAL && difference.width()) { 1483 if (element->isFormControlElement()) { 1484 // Make implicit margins from the theme explicit (see <http://bugs.webkit.org/show_bug.cgi?id=9547>). 1485 style->setProperty(CSSPropertyMarginLeft, String::number(renderer->marginLeft() / zoomFactor) + "px", false, ec); 1486 style->setProperty(CSSPropertyMarginRight, String::number(renderer->marginRight() / zoomFactor) + "px", false, ec); 1487 } 1488 int baseWidth = renderer->width() - (isBoxSizingBorder ? 0 1489 : renderer->borderLeft() + renderer->paddingLeft() + renderer->borderRight() + renderer->paddingRight()); 1490 baseWidth = baseWidth / zoomFactor; 1491 style->setProperty(CSSPropertyWidth, String::number(baseWidth + difference.width()) + "px", false, ec); 1492 } 1493 1494 if (resize != RESIZE_HORIZONTAL && difference.height()) { 1495 if (element->isFormControlElement()) { 1496 // Make implicit margins from the theme explicit (see <http://bugs.webkit.org/show_bug.cgi?id=9547>). 1497 style->setProperty(CSSPropertyMarginTop, String::number(renderer->marginTop() / zoomFactor) + "px", false, ec); 1498 style->setProperty(CSSPropertyMarginBottom, String::number(renderer->marginBottom() / zoomFactor) + "px", false, ec); 1499 } 1500 int baseHeight = renderer->height() - (isBoxSizingBorder ? 0 1501 : renderer->borderTop() + renderer->paddingTop() + renderer->borderBottom() + renderer->paddingBottom()); 1502 baseHeight = baseHeight / zoomFactor; 1503 style->setProperty(CSSPropertyHeight, String::number(baseHeight + difference.height()) + "px", false, ec); 1504 } 1505 1506 document->updateLayout(); 1507 1508 // FIXME (Radar 4118564): We should also autoscroll the window as necessary to keep the point under the cursor in view. 1509 } 1510 1511 void RenderLayer::valueChanged(Scrollbar*) 1512 { 1513 // Update scroll position from scrollbars. 1514 1515 bool needUpdate = false; 1516 int newX = scrollXOffset(); 1517 int newY = m_scrollY; 1518 1519 if (m_hBar) { 1520 newX = m_hBar->value(); 1521 if (newX != scrollXOffset()) 1522 needUpdate = true; 1523 } 1524 1525 if (m_vBar) { 1526 newY = m_vBar->value(); 1527 if (newY != m_scrollY) 1528 needUpdate = true; 1529 } 1530 1531 if (needUpdate) 1532 scrollToOffset(newX, newY, false); 1533 } 1534 1535 bool RenderLayer::isActive() const 1536 { 1537 Page* page = renderer()->document()->frame()->page(); 1538 return page && page->focusController()->isActive(); 1539 } 1540 1541 1542 static IntRect cornerRect(const RenderLayer* layer, const IntRect& bounds) 1543 { 1544 int horizontalThickness; 1545 int verticalThickness; 1546 if (!layer->verticalScrollbar() && !layer->horizontalScrollbar()) { 1547 // FIXME: This isn't right. We need to know the thickness of custom scrollbars 1548 // even when they don't exist in order to set the resizer square size properly. 1549 horizontalThickness = ScrollbarTheme::nativeTheme()->scrollbarThickness(); 1550 verticalThickness = horizontalThickness; 1551 } else if (layer->verticalScrollbar() && !layer->horizontalScrollbar()) { 1552 horizontalThickness = layer->verticalScrollbar()->width(); 1553 verticalThickness = horizontalThickness; 1554 } else if (layer->horizontalScrollbar() && !layer->verticalScrollbar()) { 1555 verticalThickness = layer->horizontalScrollbar()->height(); 1556 horizontalThickness = verticalThickness; 1557 } else { 1558 horizontalThickness = layer->verticalScrollbar()->width(); 1559 verticalThickness = layer->horizontalScrollbar()->height(); 1560 } 1561 return IntRect(bounds.right() - horizontalThickness - layer->renderer()->style()->borderRightWidth(), 1562 bounds.bottom() - verticalThickness - layer->renderer()->style()->borderBottomWidth(), 1563 horizontalThickness, verticalThickness); 1564 } 1565 1566 static IntRect scrollCornerRect(const RenderLayer* layer, const IntRect& bounds) 1567 { 1568 // We have a scrollbar corner when a scrollbar is visible and not filling the entire length of the box. 1569 // This happens when: 1570 // (a) A resizer is present and at least one scrollbar is present 1571 // (b) Both scrollbars are present. 1572 bool hasHorizontalBar = layer->horizontalScrollbar(); 1573 bool hasVerticalBar = layer->verticalScrollbar(); 1574 bool hasResizer = layer->renderer()->style()->resize() != RESIZE_NONE; 1575 if ((hasHorizontalBar && hasVerticalBar) || (hasResizer && (hasHorizontalBar || hasVerticalBar))) 1576 return cornerRect(layer, bounds); 1577 return IntRect(); 1578 } 1579 1580 static IntRect resizerCornerRect(const RenderLayer* layer, const IntRect& bounds) 1581 { 1582 ASSERT(layer->renderer()->isBox()); 1583 if (layer->renderer()->style()->resize() == RESIZE_NONE) 1584 return IntRect(); 1585 return cornerRect(layer, bounds); 1586 } 1587 1588 bool RenderLayer::scrollbarCornerPresent() const 1589 { 1590 ASSERT(renderer()->isBox()); 1591 return !scrollCornerRect(this, renderBox()->borderBoxRect()).isEmpty(); 1592 } 1593 1594 IntRect RenderLayer::convertFromScrollbarToContainingView(const Scrollbar* scrollbar, const IntRect& scrollbarRect) const 1595 { 1596 RenderView* view = renderer()->view(); 1597 if (!view) 1598 return scrollbarRect; 1599 1600 IntRect rect = scrollbarRect; 1601 rect.move(scrollbarOffset(scrollbar)); 1602 1603 return view->frameView()->convertFromRenderer(renderer(), rect); 1604 } 1605 1606 IntRect RenderLayer::convertFromContainingViewToScrollbar(const Scrollbar* scrollbar, const IntRect& parentRect) const 1607 { 1608 RenderView* view = renderer()->view(); 1609 if (!view) 1610 return parentRect; 1611 1612 IntRect rect = view->frameView()->convertToRenderer(renderer(), parentRect); 1613 rect.move(-scrollbarOffset(scrollbar)); 1614 return rect; 1615 } 1616 1617 IntPoint RenderLayer::convertFromScrollbarToContainingView(const Scrollbar* scrollbar, const IntPoint& scrollbarPoint) const 1618 { 1619 RenderView* view = renderer()->view(); 1620 if (!view) 1621 return scrollbarPoint; 1622 1623 IntPoint point = scrollbarPoint; 1624 point.move(scrollbarOffset(scrollbar)); 1625 return view->frameView()->convertFromRenderer(renderer(), point); 1626 } 1627 1628 IntPoint RenderLayer::convertFromContainingViewToScrollbar(const Scrollbar* scrollbar, const IntPoint& parentPoint) const 1629 { 1630 RenderView* view = renderer()->view(); 1631 if (!view) 1632 return parentPoint; 1633 1634 IntPoint point = view->frameView()->convertToRenderer(renderer(), parentPoint); 1635 1636 point.move(-scrollbarOffset(scrollbar)); 1637 return point; 1638 } 1639 1640 IntSize RenderLayer::scrollbarOffset(const Scrollbar* scrollbar) const 1641 { 1642 RenderBox* box = renderBox(); 1643 1644 if (scrollbar == m_vBar.get()) 1645 return IntSize(box->width() - box->borderRight() - scrollbar->width(), box->borderTop()); 1646 1647 if (scrollbar == m_hBar.get()) 1648 return IntSize(box->borderLeft(), box->height() - box->borderBottom() - scrollbar->height()); 1649 1650 ASSERT_NOT_REACHED(); 1651 return IntSize(); 1652 } 1653 1654 void RenderLayer::invalidateScrollbarRect(Scrollbar* scrollbar, const IntRect& rect) 1655 { 1656 IntRect scrollRect = rect; 1657 RenderBox* box = renderBox(); 1658 ASSERT(box); 1659 if (scrollbar == m_vBar.get()) 1660 scrollRect.move(box->width() - box->borderRight() - scrollbar->width(), box->borderTop()); 1661 else 1662 scrollRect.move(box->borderLeft(), box->height() - box->borderBottom() - scrollbar->height()); 1663 renderer()->repaintRectangle(scrollRect); 1664 } 1665 1666 PassRefPtr<Scrollbar> RenderLayer::createScrollbar(ScrollbarOrientation orientation) 1667 { 1668 RefPtr<Scrollbar> widget; 1669 RenderObject* actualRenderer = renderer()->node() ? renderer()->node()->shadowAncestorNode()->renderer() : renderer(); 1670 bool hasCustomScrollbarStyle = actualRenderer->isBox() && actualRenderer->style()->hasPseudoStyle(SCROLLBAR); 1671 if (hasCustomScrollbarStyle) 1672 widget = RenderScrollbar::createCustomScrollbar(this, orientation, toRenderBox(actualRenderer)); 1673 else 1674 widget = Scrollbar::createNativeScrollbar(this, orientation, RegularScrollbar); 1675 renderer()->document()->view()->addChild(widget.get()); 1676 return widget.release(); 1677 } 1678 1679 void RenderLayer::destroyScrollbar(ScrollbarOrientation orientation) 1680 { 1681 RefPtr<Scrollbar>& scrollbar = orientation == HorizontalScrollbar ? m_hBar : m_vBar; 1682 if (scrollbar) { 1683 scrollbar->removeFromParent(); 1684 scrollbar->setClient(0); 1685 scrollbar = 0; 1686 } 1687 } 1688 1689 void RenderLayer::setHasHorizontalScrollbar(bool hasScrollbar) 1690 { 1691 if (hasScrollbar == (m_hBar != 0)) 1692 return; 1693 1694 if (hasScrollbar) 1695 m_hBar = createScrollbar(HorizontalScrollbar); 1696 else 1697 destroyScrollbar(HorizontalScrollbar); 1698 1699 // Destroying or creating one bar can cause our scrollbar corner to come and go. We need to update the opposite scrollbar's style. 1700 if (m_hBar) 1701 m_hBar->styleChanged(); 1702 if (m_vBar) 1703 m_vBar->styleChanged(); 1704 1705 #if ENABLE(DASHBOARD_SUPPORT) 1706 // Force an update since we know the scrollbars have changed things. 1707 if (renderer()->document()->hasDashboardRegions()) 1708 renderer()->document()->setDashboardRegionsDirty(true); 1709 #endif 1710 } 1711 1712 void RenderLayer::setHasVerticalScrollbar(bool hasScrollbar) 1713 { 1714 if (hasScrollbar == (m_vBar != 0)) 1715 return; 1716 1717 if (hasScrollbar) 1718 m_vBar = createScrollbar(VerticalScrollbar); 1719 else 1720 destroyScrollbar(VerticalScrollbar); 1721 1722 // Destroying or creating one bar can cause our scrollbar corner to come and go. We need to update the opposite scrollbar's style. 1723 if (m_hBar) 1724 m_hBar->styleChanged(); 1725 if (m_vBar) 1726 m_vBar->styleChanged(); 1727 1728 #if ENABLE(DASHBOARD_SUPPORT) 1729 // Force an update since we know the scrollbars have changed things. 1730 if (renderer()->document()->hasDashboardRegions()) 1731 renderer()->document()->setDashboardRegionsDirty(true); 1732 #endif 1733 } 1734 1735 int RenderLayer::verticalScrollbarWidth() const 1736 { 1737 if (!m_vBar) 1738 return 0; 1739 return m_vBar->width(); 1740 } 1741 1742 int RenderLayer::horizontalScrollbarHeight() const 1743 { 1744 if (!m_hBar) 1745 return 0; 1746 return m_hBar->height(); 1747 } 1748 1749 IntSize RenderLayer::offsetFromResizeCorner(const IntPoint& absolutePoint) const 1750 { 1751 // Currently the resize corner is always the bottom right corner 1752 IntPoint bottomRight(width(), height()); 1753 IntPoint localPoint = absoluteToContents(absolutePoint); 1754 return localPoint - bottomRight; 1755 } 1756 1757 bool RenderLayer::hasOverflowControls() const 1758 { 1759 return m_hBar || m_vBar || m_scrollCorner || renderer()->style()->resize() != RESIZE_NONE; 1760 } 1761 1762 void RenderLayer::positionOverflowControls(int tx, int ty) 1763 { 1764 if (!m_hBar && !m_vBar && (!renderer()->hasOverflowClip() || renderer()->style()->resize() == RESIZE_NONE)) 1765 return; 1766 1767 RenderBox* box = renderBox(); 1768 if (!box) 1769 return; 1770 1771 IntRect borderBox = box->borderBoxRect(); 1772 IntRect scrollCorner(scrollCornerRect(this, borderBox)); 1773 IntRect absBounds(borderBox.x() + tx, borderBox.y() + ty, borderBox.width(), borderBox.height()); 1774 if (m_vBar) 1775 m_vBar->setFrameRect(IntRect(absBounds.right() - box->borderRight() - m_vBar->width(), 1776 absBounds.y() + box->borderTop(), 1777 m_vBar->width(), 1778 absBounds.height() - (box->borderTop() + box->borderBottom()) - scrollCorner.height())); 1779 1780 if (m_hBar) 1781 m_hBar->setFrameRect(IntRect(absBounds.x() + box->borderLeft(), 1782 absBounds.bottom() - box->borderBottom() - m_hBar->height(), 1783 absBounds.width() - (box->borderLeft() + box->borderRight()) - scrollCorner.width(), 1784 m_hBar->height())); 1785 1786 if (m_scrollCorner) 1787 m_scrollCorner->setFrameRect(scrollCorner); 1788 if (m_resizer) 1789 m_resizer->setFrameRect(resizerCornerRect(this, borderBox)); 1790 } 1791 1792 int RenderLayer::scrollWidth() 1793 { 1794 if (m_scrollDimensionsDirty) 1795 computeScrollDimensions(); 1796 return m_scrollWidth; 1797 } 1798 1799 int RenderLayer::scrollHeight() 1800 { 1801 if (m_scrollDimensionsDirty) 1802 computeScrollDimensions(); 1803 return m_scrollHeight; 1804 } 1805 1806 void RenderLayer::computeScrollDimensions(bool* needHBar, bool* needVBar) 1807 { 1808 RenderBox* box = renderBox(); 1809 ASSERT(box); 1810 1811 m_scrollDimensionsDirty = false; 1812 1813 bool ltr = renderer()->style()->direction() == LTR; 1814 1815 int clientWidth = box->clientWidth(); 1816 int clientHeight = box->clientHeight(); 1817 1818 m_scrollLeftOverflow = ltr ? 0 : min(0, box->leftmostPosition(true, false) - box->borderLeft()); 1819 1820 int rightPos = ltr ? 1821 box->rightmostPosition(true, false) - box->borderLeft() : 1822 clientWidth - m_scrollLeftOverflow; 1823 int bottomPos = box->lowestPosition(true, false) - box->borderTop(); 1824 1825 m_scrollWidth = max(rightPos, clientWidth); 1826 m_scrollHeight = max(bottomPos, clientHeight); 1827 1828 m_scrollOriginX = ltr ? 0 : m_scrollWidth - clientWidth; 1829 1830 if (needHBar) 1831 *needHBar = rightPos > clientWidth; 1832 if (needVBar) 1833 *needVBar = bottomPos > clientHeight; 1834 } 1835 1836 void RenderLayer::updateOverflowStatus(bool horizontalOverflow, bool verticalOverflow) 1837 { 1838 if (m_overflowStatusDirty) { 1839 m_horizontalOverflow = horizontalOverflow; 1840 m_verticalOverflow = verticalOverflow; 1841 m_overflowStatusDirty = false; 1842 1843 return; 1844 } 1845 1846 bool horizontalOverflowChanged = (m_horizontalOverflow != horizontalOverflow); 1847 bool verticalOverflowChanged = (m_verticalOverflow != verticalOverflow); 1848 1849 if (horizontalOverflowChanged || verticalOverflowChanged) { 1850 m_horizontalOverflow = horizontalOverflow; 1851 m_verticalOverflow = verticalOverflow; 1852 1853 if (FrameView* frameView = renderer()->document()->view()) { 1854 frameView->scheduleEvent(OverflowEvent::create(horizontalOverflowChanged, horizontalOverflow, verticalOverflowChanged, verticalOverflow), 1855 renderer()->node()); 1856 } 1857 } 1858 } 1859 1860 void 1861 RenderLayer::updateScrollInfoAfterLayout() 1862 { 1863 RenderBox* box = renderBox(); 1864 if (!box) 1865 return; 1866 1867 m_scrollDimensionsDirty = true; 1868 1869 bool horizontalOverflow, verticalOverflow; 1870 computeScrollDimensions(&horizontalOverflow, &verticalOverflow); 1871 1872 if (box->style()->overflowX() != OMARQUEE) { 1873 // Layout may cause us to be in an invalid scroll position. In this case we need 1874 // to pull our scroll offsets back to the max (or push them up to the min). 1875 int newX = max(0, min(scrollXOffset(), scrollWidth() - box->clientWidth())); 1876 int newY = max(0, min(m_scrollY, scrollHeight() - box->clientHeight())); 1877 if (newX != scrollXOffset() || newY != m_scrollY) { 1878 RenderView* view = renderer()->view(); 1879 ASSERT(view); 1880 // scrollToOffset() may call updateLayerPositions(), which doesn't work 1881 // with LayoutState. 1882 // FIXME: Remove the disableLayoutState/enableLayoutState if the above changes. 1883 if (view) 1884 view->disableLayoutState(); 1885 scrollToOffset(newX, newY); 1886 if (view) 1887 view->enableLayoutState(); 1888 } 1889 } 1890 1891 bool haveHorizontalBar = m_hBar; 1892 bool haveVerticalBar = m_vBar; 1893 1894 // overflow:scroll should just enable/disable. 1895 if (renderer()->style()->overflowX() == OSCROLL) 1896 m_hBar->setEnabled(horizontalOverflow); 1897 if (renderer()->style()->overflowY() == OSCROLL) 1898 m_vBar->setEnabled(verticalOverflow); 1899 1900 // A dynamic change from a scrolling overflow to overflow:hidden means we need to get rid of any 1901 // scrollbars that may be present. 1902 if (renderer()->style()->overflowX() == OHIDDEN && haveHorizontalBar) 1903 setHasHorizontalScrollbar(false); 1904 if (renderer()->style()->overflowY() == OHIDDEN && haveVerticalBar) 1905 setHasVerticalScrollbar(false); 1906 1907 // overflow:auto may need to lay out again if scrollbars got added/removed. 1908 bool scrollbarsChanged = (box->hasAutoHorizontalScrollbar() && haveHorizontalBar != horizontalOverflow) || 1909 (box->hasAutoVerticalScrollbar() && haveVerticalBar != verticalOverflow); 1910 if (scrollbarsChanged) { 1911 if (box->hasAutoHorizontalScrollbar()) 1912 setHasHorizontalScrollbar(horizontalOverflow); 1913 if (box->hasAutoVerticalScrollbar()) 1914 setHasVerticalScrollbar(verticalOverflow); 1915 1916 #if ENABLE(DASHBOARD_SUPPORT) 1917 // Force an update since we know the scrollbars have changed things. 1918 if (renderer()->document()->hasDashboardRegions()) 1919 renderer()->document()->setDashboardRegionsDirty(true); 1920 #endif 1921 1922 renderer()->repaint(); 1923 1924 if (renderer()->style()->overflowX() == OAUTO || renderer()->style()->overflowY() == OAUTO) { 1925 if (!m_inOverflowRelayout) { 1926 // Our proprietary overflow: overlay value doesn't trigger a layout. 1927 m_inOverflowRelayout = true; 1928 renderer()->setNeedsLayout(true, false); 1929 if (renderer()->isRenderBlock()) 1930 toRenderBlock(renderer())->layoutBlock(true); 1931 else 1932 renderer()->layout(); 1933 m_inOverflowRelayout = false; 1934 } 1935 } 1936 } 1937 1938 // If overflow:scroll is turned into overflow:auto a bar might still be disabled (Bug 11985). 1939 if (m_hBar && box->hasAutoHorizontalScrollbar()) 1940 m_hBar->setEnabled(true); 1941 if (m_vBar && box->hasAutoVerticalScrollbar()) 1942 m_vBar->setEnabled(true); 1943 1944 // Set up the range (and page step/line step). 1945 if (m_hBar) { 1946 int clientWidth = box->clientWidth(); 1947 int pageStep = max(max<int>(clientWidth * Scrollbar::minFractionToStepWhenPaging(), clientWidth - Scrollbar::maxOverlapBetweenPages()), 1); 1948 m_hBar->setSteps(Scrollbar::pixelsPerLineStep(), pageStep); 1949 m_hBar->setProportion(clientWidth, m_scrollWidth); 1950 // Explicitly set the horizontal scroll value. This ensures that when a 1951 // right-to-left scrollable area's width (or content width) changes, the 1952 // top right corner of the content doesn't shift with respect to the top 1953 // right corner of the area. Conceptually, right-to-left areas have 1954 // their origin at the top-right, but RenderLayer is top-left oriented, 1955 // so this is needed to keep everything working (see how scrollXOffset() 1956 // differs from scrollYOffset() to get an idea of why the horizontal and 1957 // vertical scrollbars need to be treated differently). 1958 m_hBar->setValue(scrollXOffset()); 1959 } 1960 if (m_vBar) { 1961 int clientHeight = box->clientHeight(); 1962 int pageStep = max(max<int>(clientHeight * Scrollbar::minFractionToStepWhenPaging(), clientHeight - Scrollbar::maxOverlapBetweenPages()), 1); 1963 m_vBar->setSteps(Scrollbar::pixelsPerLineStep(), pageStep); 1964 m_vBar->setProportion(clientHeight, m_scrollHeight); 1965 } 1966 1967 if (renderer()->node() && renderer()->document()->hasListenerType(Document::OVERFLOWCHANGED_LISTENER)) 1968 updateOverflowStatus(horizontalOverflow, verticalOverflow); 1969 } 1970 1971 void RenderLayer::paintOverflowControls(GraphicsContext* context, int tx, int ty, const IntRect& damageRect) 1972 { 1973 // Don't do anything if we have no overflow. 1974 if (!renderer()->hasOverflowClip()) 1975 return; 1976 1977 // Move the scrollbar widgets if necessary. We normally move and resize widgets during layout, but sometimes 1978 // widgets can move without layout occurring (most notably when you scroll a document that 1979 // contains fixed positioned elements). 1980 positionOverflowControls(tx, ty); 1981 1982 // Now that we're sure the scrollbars are in the right place, paint them. 1983 if (m_hBar) 1984 m_hBar->paint(context, damageRect); 1985 if (m_vBar) 1986 m_vBar->paint(context, damageRect); 1987 1988 // We fill our scroll corner with white if we have a scrollbar that doesn't run all the way up to the 1989 // edge of the box. 1990 paintScrollCorner(context, tx, ty, damageRect); 1991 1992 // Paint our resizer last, since it sits on top of the scroll corner. 1993 paintResizer(context, tx, ty, damageRect); 1994 } 1995 1996 void RenderLayer::paintScrollCorner(GraphicsContext* context, int tx, int ty, const IntRect& damageRect) 1997 { 1998 RenderBox* box = renderBox(); 1999 ASSERT(box); 2000 2001 IntRect cornerRect = scrollCornerRect(this, box->borderBoxRect()); 2002 IntRect absRect = IntRect(cornerRect.x() + tx, cornerRect.y() + ty, cornerRect.width(), cornerRect.height()); 2003 if (!absRect.intersects(damageRect)) 2004 return; 2005 2006 if (context->updatingControlTints()) { 2007 updateScrollCornerStyle(); 2008 return; 2009 } 2010 2011 if (m_scrollCorner) { 2012 m_scrollCorner->paintIntoRect(context, tx, ty, absRect); 2013 return; 2014 } 2015 2016 context->fillRect(absRect, Color::white, box->style()->colorSpace()); 2017 } 2018 2019 void RenderLayer::paintResizer(GraphicsContext* context, int tx, int ty, const IntRect& damageRect) 2020 { 2021 if (renderer()->style()->resize() == RESIZE_NONE) 2022 return; 2023 2024 RenderBox* box = renderBox(); 2025 ASSERT(box); 2026 2027 IntRect cornerRect = resizerCornerRect(this, box->borderBoxRect()); 2028 IntRect absRect = IntRect(cornerRect.x() + tx, cornerRect.y() + ty, cornerRect.width(), cornerRect.height()); 2029 if (!absRect.intersects(damageRect)) 2030 return; 2031 2032 if (context->updatingControlTints()) { 2033 updateResizerStyle(); 2034 return; 2035 } 2036 2037 if (m_resizer) { 2038 m_resizer->paintIntoRect(context, tx, ty, absRect); 2039 return; 2040 } 2041 2042 // Paint the resizer control. 2043 DEFINE_STATIC_LOCAL(RefPtr<Image>, resizeCornerImage, (Image::loadPlatformResource("textAreaResizeCorner"))); 2044 IntPoint imagePoint(absRect.right() - resizeCornerImage->width(), absRect.bottom() - resizeCornerImage->height()); 2045 context->drawImage(resizeCornerImage.get(), box->style()->colorSpace(), imagePoint); 2046 2047 // Draw a frame around the resizer (1px grey line) if there are any scrollbars present. 2048 // Clipping will exclude the right and bottom edges of this frame. 2049 if (m_hBar || m_vBar) { 2050 context->save(); 2051 context->clip(absRect); 2052 IntRect largerCorner = absRect; 2053 largerCorner.setSize(IntSize(largerCorner.width() + 1, largerCorner.height() + 1)); 2054 context->setStrokeColor(Color(makeRGB(217, 217, 217)), DeviceColorSpace); 2055 context->setStrokeThickness(1.0f); 2056 context->setFillColor(Color::transparent, DeviceColorSpace); 2057 context->drawRect(largerCorner); 2058 context->restore(); 2059 } 2060 } 2061 2062 bool RenderLayer::isPointInResizeControl(const IntPoint& absolutePoint) const 2063 { 2064 if (!renderer()->hasOverflowClip() || renderer()->style()->resize() == RESIZE_NONE) 2065 return false; 2066 2067 RenderBox* box = renderBox(); 2068 ASSERT(box); 2069 2070 IntPoint localPoint = absoluteToContents(absolutePoint); 2071 2072 IntRect localBounds(0, 0, box->width(), box->height()); 2073 return resizerCornerRect(this, localBounds).contains(localPoint); 2074 } 2075 2076 bool RenderLayer::hitTestOverflowControls(HitTestResult& result, const IntPoint& localPoint) 2077 { 2078 if (!m_hBar && !m_vBar && (!renderer()->hasOverflowClip() || renderer()->style()->resize() == RESIZE_NONE)) 2079 return false; 2080 2081 RenderBox* box = renderBox(); 2082 ASSERT(box); 2083 2084 IntRect resizeControlRect; 2085 if (renderer()->style()->resize() != RESIZE_NONE) { 2086 resizeControlRect = resizerCornerRect(this, box->borderBoxRect()); 2087 if (resizeControlRect.contains(localPoint)) 2088 return true; 2089 } 2090 2091 int resizeControlSize = max(resizeControlRect.height(), 0); 2092 2093 if (m_vBar) { 2094 IntRect vBarRect(box->width() - box->borderRight() - m_vBar->width(), 2095 box->borderTop(), 2096 m_vBar->width(), 2097 box->height() - (box->borderTop() + box->borderBottom()) - (m_hBar ? m_hBar->height() : resizeControlSize)); 2098 if (vBarRect.contains(localPoint)) { 2099 result.setScrollbar(m_vBar.get()); 2100 return true; 2101 } 2102 } 2103 2104 resizeControlSize = max(resizeControlRect.width(), 0); 2105 if (m_hBar) { 2106 IntRect hBarRect(box->borderLeft(), 2107 box->height() - box->borderBottom() - m_hBar->height(), 2108 box->width() - (box->borderLeft() + box->borderRight()) - (m_vBar ? m_vBar->width() : resizeControlSize), 2109 m_hBar->height()); 2110 if (hBarRect.contains(localPoint)) { 2111 result.setScrollbar(m_hBar.get()); 2112 return true; 2113 } 2114 } 2115 2116 return false; 2117 } 2118 2119 bool RenderLayer::scroll(ScrollDirection direction, ScrollGranularity granularity, float multiplier) 2120 { 2121 bool didHorizontalScroll = false; 2122 bool didVerticalScroll = false; 2123 2124 if (m_hBar) { 2125 if (granularity == ScrollByDocument) { 2126 // Special-case for the ScrollByDocument granularity. A document scroll can only be up 2127 // or down and in both cases the horizontal bar goes all the way to the left. 2128 didHorizontalScroll = m_hBar->scroll(ScrollLeft, ScrollByDocument, multiplier); 2129 } else 2130 didHorizontalScroll = m_hBar->scroll(direction, granularity, multiplier); 2131 } 2132 2133 if (m_vBar) 2134 didVerticalScroll = m_vBar->scroll(direction, granularity, multiplier); 2135 2136 return (didHorizontalScroll || didVerticalScroll); 2137 } 2138 2139 void RenderLayer::paint(GraphicsContext* p, const IntRect& damageRect, PaintBehavior paintBehavior, RenderObject *paintingRoot) 2140 { 2141 RenderObject::OverlapTestRequestMap overlapTestRequests; 2142 paintLayer(this, p, damageRect, paintBehavior, paintingRoot, &overlapTestRequests); 2143 RenderObject::OverlapTestRequestMap::iterator end = overlapTestRequests.end(); 2144 for (RenderObject::OverlapTestRequestMap::iterator it = overlapTestRequests.begin(); it != end; ++it) 2145 it->first->setOverlapTestResult(false); 2146 } 2147 2148 static void setClip(GraphicsContext* p, const IntRect& paintDirtyRect, const IntRect& clipRect) 2149 { 2150 if (paintDirtyRect == clipRect) 2151 return; 2152 p->save(); 2153 p->clip(clipRect); 2154 } 2155 2156 static void restoreClip(GraphicsContext* p, const IntRect& paintDirtyRect, const IntRect& clipRect) 2157 { 2158 if (paintDirtyRect == clipRect) 2159 return; 2160 p->restore(); 2161 } 2162 2163 static void performOverlapTests(RenderObject::OverlapTestRequestMap& overlapTestRequests, const IntRect& layerBounds) 2164 { 2165 Vector<OverlapTestRequestClient*> overlappedRequestClients; 2166 RenderObject::OverlapTestRequestMap::iterator end = overlapTestRequests.end(); 2167 for (RenderObject::OverlapTestRequestMap::iterator it = overlapTestRequests.begin(); it != end; ++it) { 2168 if (!layerBounds.intersects(it->second)) 2169 continue; 2170 2171 it->first->setOverlapTestResult(true); 2172 overlappedRequestClients.append(it->first); 2173 } 2174 for (size_t i = 0; i < overlappedRequestClients.size(); ++i) 2175 overlapTestRequests.remove(overlappedRequestClients[i]); 2176 } 2177 2178 #if USE(ACCELERATED_COMPOSITING) 2179 static bool shouldDoSoftwarePaint(const RenderLayer* layer, bool paintingReflection) 2180 { 2181 return paintingReflection && !layer->has3DTransform(); 2182 } 2183 #endif 2184 2185 void RenderLayer::paintLayer(RenderLayer* rootLayer, GraphicsContext* p, 2186 const IntRect& paintDirtyRect, PaintBehavior paintBehavior, 2187 RenderObject* paintingRoot, RenderObject::OverlapTestRequestMap* overlapTestRequests, 2188 PaintLayerFlags paintFlags) 2189 { 2190 #if USE(ACCELERATED_COMPOSITING) 2191 if (isComposited()) { 2192 // The updatingControlTints() painting pass goes through compositing layers, 2193 // but we need to ensure that we don't cache clip rects computed with the wrong root in this case. 2194 if (p->updatingControlTints() || (paintBehavior & PaintBehaviorFlattenCompositingLayers)) 2195 paintFlags |= PaintLayerTemporaryClipRects; 2196 else if (!backing()->paintingGoesToWindow() && !shouldDoSoftwarePaint(this, paintFlags & PaintLayerPaintingReflection)) { 2197 // If this RenderLayer should paint into its backing, that will be done via RenderLayerBacking::paintIntoLayer(). 2198 return; 2199 } 2200 } 2201 #endif 2202 2203 // Avoid painting layers when stylesheets haven't loaded. This eliminates FOUC. 2204 // It's ok not to draw, because later on, when all the stylesheets do load, updateStyleSelector on the Document 2205 // will do a full repaint(). 2206 if (renderer()->document()->didLayoutWithPendingStylesheets() && !renderer()->isRenderView() && !renderer()->isRoot()) 2207 return; 2208 2209 // If this layer is totally invisible then there is nothing to paint. 2210 if (!renderer()->opacity()) 2211 return; 2212 2213 if (paintsWithTransparency(paintBehavior)) 2214 paintFlags |= PaintLayerHaveTransparency; 2215 2216 // Apply a transform if we have one. A reflection is considered to be a transform, since it is a flip and a translate. 2217 if (paintsWithTransform(paintBehavior) && !(paintFlags & PaintLayerAppliedTransform)) { 2218 TransformationMatrix layerTransform = renderableTransform(paintBehavior); 2219 // If the transform can't be inverted, then don't paint anything. 2220 if (!layerTransform.isInvertible()) 2221 return; 2222 2223 // If we have a transparency layer enclosing us and we are the root of a transform, then we need to establish the transparency 2224 // layer from the parent now. 2225 if (paintFlags & PaintLayerHaveTransparency) 2226 parent()->beginTransparencyLayers(p, rootLayer, paintBehavior); 2227 2228 // Make sure the parent's clip rects have been calculated. 2229 IntRect clipRect = paintDirtyRect; 2230 if (parent()) { 2231 clipRect = backgroundClipRect(rootLayer, paintFlags & PaintLayerTemporaryClipRects); 2232 clipRect.intersect(paintDirtyRect); 2233 } 2234 2235 // Push the parent coordinate space's clip. 2236 setClip(p, paintDirtyRect, clipRect); 2237 2238 // Adjust the transform such that the renderer's upper left corner will paint at (0,0) in user space. 2239 // This involves subtracting out the position of the layer in our current coordinate space. 2240 int x = 0; 2241 int y = 0; 2242 convertToLayerCoords(rootLayer, x, y); 2243 TransformationMatrix transform(layerTransform); 2244 transform.translateRight(x, y); 2245 2246 // Apply the transform. 2247 p->save(); 2248 p->concatCTM(transform.toAffineTransform()); 2249 2250 // Now do a paint with the root layer shifted to be us. 2251 paintLayer(this, p, transform.inverse().mapRect(paintDirtyRect), paintBehavior, paintingRoot, overlapTestRequests, paintFlags | PaintLayerAppliedTransform); 2252 2253 p->restore(); 2254 2255 // Restore the clip. 2256 restoreClip(p, paintDirtyRect, clipRect); 2257 2258 return; 2259 } 2260 2261 PaintLayerFlags localPaintFlags = paintFlags & ~PaintLayerAppliedTransform; 2262 bool haveTransparency = localPaintFlags & PaintLayerHaveTransparency; 2263 2264 // Paint the reflection first if we have one. 2265 if (m_reflection && !m_paintingInsideReflection) { 2266 // Mark that we are now inside replica painting. 2267 m_paintingInsideReflection = true; 2268 reflectionLayer()->paintLayer(rootLayer, p, paintDirtyRect, paintBehavior, paintingRoot, overlapTestRequests, localPaintFlags | PaintLayerPaintingReflection); 2269 m_paintingInsideReflection = false; 2270 } 2271 2272 // Calculate the clip rects we should use. 2273 IntRect layerBounds, damageRect, clipRectToApply, outlineRect; 2274 calculateRects(rootLayer, paintDirtyRect, layerBounds, damageRect, clipRectToApply, outlineRect, localPaintFlags & PaintLayerTemporaryClipRects); 2275 int x = layerBounds.x(); 2276 int y = layerBounds.y(); 2277 int tx = x - renderBoxX(); 2278 int ty = y - renderBoxY(); 2279 2280 // Ensure our lists are up-to-date. 2281 updateCompositingAndLayerListsIfNeeded(); 2282 2283 bool forceBlackText = paintBehavior & PaintBehaviorForceBlackText; 2284 bool selectionOnly = paintBehavior & PaintBehaviorSelectionOnly; 2285 2286 // If this layer's renderer is a child of the paintingRoot, we render unconditionally, which 2287 // is done by passing a nil paintingRoot down to our renderer (as if no paintingRoot was ever set). 2288 // Else, our renderer tree may or may not contain the painting root, so we pass that root along 2289 // so it will be tested against as we descend through the renderers. 2290 RenderObject* paintingRootForRenderer = 0; 2291 if (paintingRoot && !renderer()->isDescendantOf(paintingRoot)) 2292 paintingRootForRenderer = paintingRoot; 2293 2294 if (overlapTestRequests) 2295 performOverlapTests(*overlapTestRequests, layerBounds); 2296 2297 // We want to paint our layer, but only if we intersect the damage rect. 2298 bool shouldPaint = intersectsDamageRect(layerBounds, damageRect, rootLayer) && m_hasVisibleContent && isSelfPaintingLayer(); 2299 if (shouldPaint && !selectionOnly && !damageRect.isEmpty()) { 2300 // Begin transparency layers lazily now that we know we have to paint something. 2301 if (haveTransparency) 2302 beginTransparencyLayers(p, rootLayer, paintBehavior); 2303 2304 // Paint our background first, before painting any child layers. 2305 // Establish the clip used to paint our background. 2306 setClip(p, paintDirtyRect, damageRect); 2307 2308 // Paint the background. 2309 RenderObject::PaintInfo paintInfo(p, damageRect, PaintPhaseBlockBackground, false, paintingRootForRenderer, 0); 2310 renderer()->paint(paintInfo, tx, ty); 2311 2312 // Restore the clip. 2313 restoreClip(p, paintDirtyRect, damageRect); 2314 } 2315 2316 // Now walk the sorted list of children with negative z-indices. 2317 if (m_negZOrderList) 2318 for (Vector<RenderLayer*>::iterator it = m_negZOrderList->begin(); it != m_negZOrderList->end(); ++it) 2319 it[0]->paintLayer(rootLayer, p, paintDirtyRect, paintBehavior, paintingRoot, overlapTestRequests, localPaintFlags); 2320 2321 // Now establish the appropriate clip and paint our child RenderObjects. 2322 if (shouldPaint && !clipRectToApply.isEmpty()) { 2323 // Begin transparency layers lazily now that we know we have to paint something. 2324 if (haveTransparency) 2325 beginTransparencyLayers(p, rootLayer, paintBehavior); 2326 2327 // Set up the clip used when painting our children. 2328 setClip(p, paintDirtyRect, clipRectToApply); 2329 RenderObject::PaintInfo paintInfo(p, clipRectToApply, 2330 selectionOnly ? PaintPhaseSelection : PaintPhaseChildBlockBackgrounds, 2331 forceBlackText, paintingRootForRenderer, 0); 2332 renderer()->paint(paintInfo, tx, ty); 2333 if (!selectionOnly) { 2334 paintInfo.phase = PaintPhaseFloat; 2335 renderer()->paint(paintInfo, tx, ty); 2336 paintInfo.phase = PaintPhaseForeground; 2337 paintInfo.overlapTestRequests = overlapTestRequests; 2338 renderer()->paint(paintInfo, tx, ty); 2339 paintInfo.phase = PaintPhaseChildOutlines; 2340 renderer()->paint(paintInfo, tx, ty); 2341 } 2342 2343 // Now restore our clip. 2344 restoreClip(p, paintDirtyRect, clipRectToApply); 2345 } 2346 2347 if (!outlineRect.isEmpty() && isSelfPaintingLayer()) { 2348 // Paint our own outline 2349 RenderObject::PaintInfo paintInfo(p, outlineRect, PaintPhaseSelfOutline, false, paintingRootForRenderer, 0); 2350 setClip(p, paintDirtyRect, outlineRect); 2351 renderer()->paint(paintInfo, tx, ty); 2352 restoreClip(p, paintDirtyRect, outlineRect); 2353 } 2354 2355 // Paint any child layers that have overflow. 2356 if (m_normalFlowList) 2357 for (Vector<RenderLayer*>::iterator it = m_normalFlowList->begin(); it != m_normalFlowList->end(); ++it) 2358 it[0]->paintLayer(rootLayer, p, paintDirtyRect, paintBehavior, paintingRoot, overlapTestRequests, localPaintFlags); 2359 2360 // Now walk the sorted list of children with positive z-indices. 2361 if (m_posZOrderList) 2362 for (Vector<RenderLayer*>::iterator it = m_posZOrderList->begin(); it != m_posZOrderList->end(); ++it) 2363 it[0]->paintLayer(rootLayer, p, paintDirtyRect, paintBehavior, paintingRoot, overlapTestRequests, localPaintFlags); 2364 2365 if (renderer()->hasMask() && shouldPaint && !selectionOnly && !damageRect.isEmpty()) { 2366 setClip(p, paintDirtyRect, damageRect); 2367 2368 // Paint the mask. 2369 RenderObject::PaintInfo paintInfo(p, damageRect, PaintPhaseMask, false, paintingRootForRenderer, 0); 2370 renderer()->paint(paintInfo, tx, ty); 2371 2372 // Restore the clip. 2373 restoreClip(p, paintDirtyRect, damageRect); 2374 } 2375 2376 // End our transparency layer 2377 if (haveTransparency && m_usedTransparency && !m_paintingInsideReflection) { 2378 p->endTransparencyLayer(); 2379 p->restore(); 2380 m_usedTransparency = false; 2381 } 2382 } 2383 2384 static inline IntRect frameVisibleRect(RenderObject* renderer) 2385 { 2386 FrameView* frameView = renderer->document()->view(); 2387 if (!frameView) 2388 return IntRect(); 2389 2390 return frameView->visibleContentRect(); 2391 } 2392 2393 bool RenderLayer::hitTest(const HitTestRequest& request, HitTestResult& result) 2394 { 2395 renderer()->document()->updateLayout(); 2396 2397 IntRect boundsRect(m_x, m_y, width(), height()); 2398 if (!request.ignoreClipping()) 2399 boundsRect.intersect(frameVisibleRect(renderer())); 2400 2401 RenderLayer* insideLayer = hitTestLayer(this, 0, request, result, boundsRect, result.point(), false); 2402 if (!insideLayer) { 2403 // We didn't hit any layer. If we are the root layer and the mouse is -- or just was -- down, 2404 // return ourselves. We do this so mouse events continue getting delivered after a drag has 2405 // exited the WebView, and so hit testing over a scrollbar hits the content document. 2406 if ((request.active() || request.mouseUp()) && renderer()->isRenderView()) { 2407 renderer()->updateHitTestResult(result, result.point()); 2408 insideLayer = this; 2409 } 2410 } 2411 2412 // Now determine if the result is inside an anchor - if the urlElement isn't already set. 2413 Node* node = result.innerNode(); 2414 if (node && !result.URLElement()) 2415 result.setURLElement(static_cast<Element*>(node->enclosingLinkEventParentOrSelf())); 2416 2417 // Next set up the correct :hover/:active state along the new chain. 2418 updateHoverActiveState(request, result); 2419 2420 // Now return whether we were inside this layer (this will always be true for the root 2421 // layer). 2422 return insideLayer; 2423 } 2424 2425 Node* RenderLayer::enclosingElement() const 2426 { 2427 for (RenderObject* r = renderer(); r; r = r->parent()) { 2428 if (Node* e = r->node()) 2429 return e; 2430 } 2431 ASSERT_NOT_REACHED(); 2432 return 0; 2433 } 2434 2435 // Compute the z-offset of the point in the transformState. 2436 // This is effectively projecting a ray normal to the plane of ancestor, finding where that 2437 // ray intersects target, and computing the z delta between those two points. 2438 static double computeZOffset(const HitTestingTransformState& transformState) 2439 { 2440 // We got an affine transform, so no z-offset 2441 if (transformState.m_accumulatedTransform.isAffine()) 2442 return 0; 2443 2444 // Flatten the point into the target plane 2445 FloatPoint targetPoint = transformState.mappedPoint(); 2446 2447 // Now map the point back through the transform, which computes Z. 2448 FloatPoint3D backmappedPoint = transformState.m_accumulatedTransform.mapPoint(FloatPoint3D(targetPoint)); 2449 return backmappedPoint.z(); 2450 } 2451 2452 PassRefPtr<HitTestingTransformState> RenderLayer::createLocalTransformState(RenderLayer* rootLayer, RenderLayer* containerLayer, 2453 const IntRect& hitTestRect, const IntPoint& hitTestPoint, 2454 const HitTestingTransformState* containerTransformState) const 2455 { 2456 RefPtr<HitTestingTransformState> transformState; 2457 int offsetX = 0; 2458 int offsetY = 0; 2459 if (containerTransformState) { 2460 // If we're already computing transform state, then it's relative to the container (which we know is non-null). 2461 transformState = HitTestingTransformState::create(*containerTransformState); 2462 convertToLayerCoords(containerLayer, offsetX, offsetY); 2463 } else { 2464 // If this is the first time we need to make transform state, then base it off of hitTestPoint, 2465 // which is relative to rootLayer. 2466 transformState = HitTestingTransformState::create(hitTestPoint, FloatQuad(hitTestRect)); 2467 convertToLayerCoords(rootLayer, offsetX, offsetY); 2468 } 2469 2470 RenderObject* containerRenderer = containerLayer ? containerLayer->renderer() : 0; 2471 if (renderer()->shouldUseTransformFromContainer(containerRenderer)) { 2472 TransformationMatrix containerTransform; 2473 renderer()->getTransformFromContainer(containerRenderer, IntSize(offsetX, offsetY), containerTransform); 2474 transformState->applyTransform(containerTransform, HitTestingTransformState::AccumulateTransform); 2475 } else { 2476 transformState->translate(offsetX, offsetY, HitTestingTransformState::AccumulateTransform); 2477 } 2478 2479 return transformState; 2480 } 2481 2482 2483 static bool isHitCandidate(const RenderLayer* hitLayer, bool canDepthSort, double* zOffset, const HitTestingTransformState* transformState) 2484 { 2485 if (!hitLayer) 2486 return false; 2487 2488 // The hit layer is depth-sorting with other layers, so just say that it was hit. 2489 if (canDepthSort) 2490 return true; 2491 2492 // We need to look at z-depth to decide if this layer was hit. 2493 if (zOffset) { 2494 ASSERT(transformState); 2495 // This is actually computing our z, but that's OK because the hitLayer is coplanar with us. 2496 double childZOffset = computeZOffset(*transformState); 2497 if (childZOffset > *zOffset) { 2498 *zOffset = childZOffset; 2499 return true; 2500 } 2501 return false; 2502 } 2503 2504 return true; 2505 } 2506 2507 // hitTestPoint and hitTestRect are relative to rootLayer. 2508 // A 'flattening' layer is one preserves3D() == false. 2509 // transformState.m_accumulatedTransform holds the transform from the containing flattening layer. 2510 // transformState.m_lastPlanarPoint is the hitTestPoint in the plane of the containing flattening layer. 2511 // transformState.m_lastPlanarQuad is the hitTestRect as a quad in the plane of the containing flattening layer. 2512 // 2513 // If zOffset is non-null (which indicates that the caller wants z offset information), 2514 // *zOffset on return is the z offset of the hit point relative to the containing flattening layer. 2515 RenderLayer* RenderLayer::hitTestLayer(RenderLayer* rootLayer, RenderLayer* containerLayer, const HitTestRequest& request, HitTestResult& result, 2516 const IntRect& hitTestRect, const IntPoint& hitTestPoint, bool appliedTransform, 2517 const HitTestingTransformState* transformState, double* zOffset) 2518 { 2519 // The natural thing would be to keep HitTestingTransformState on the stack, but it's big, so we heap-allocate. 2520 2521 bool useTemporaryClipRects = false; 2522 #if USE(ACCELERATED_COMPOSITING) 2523 useTemporaryClipRects = compositor()->inCompositingMode(); 2524 #endif 2525 2526 // Apply a transform if we have one. 2527 if (transform() && !appliedTransform) { 2528 // Make sure the parent's clip rects have been calculated. 2529 if (parent()) { 2530 IntRect clipRect = backgroundClipRect(rootLayer, useTemporaryClipRects); 2531 // Go ahead and test the enclosing clip now. 2532 if (!clipRect.contains(hitTestPoint)) 2533 return 0; 2534 } 2535 2536 // Create a transform state to accumulate this transform. 2537 RefPtr<HitTestingTransformState> newTransformState = createLocalTransformState(rootLayer, containerLayer, hitTestRect, hitTestPoint, transformState); 2538 2539 // If the transform can't be inverted, then don't hit test this layer at all. 2540 if (!newTransformState->m_accumulatedTransform.isInvertible()) 2541 return 0; 2542 2543 // Compute the point and the hit test rect in the coords of this layer by using the values 2544 // from the transformState, which store the point and quad in the coords of the last flattened 2545 // layer, and the accumulated transform which lets up map through preserve-3d layers. 2546 // 2547 // We can't just map hitTestPoint and hitTestRect because they may have been flattened (losing z) 2548 // by our container. 2549 IntPoint localPoint = roundedIntPoint(newTransformState->mappedPoint()); 2550 IntRect localHitTestRect; 2551 #if USE(ACCELERATED_COMPOSITING) 2552 if (isComposited()) { 2553 // It doesn't make sense to project hitTestRect into the plane of this layer, so use the same bounds we use for painting. 2554 localHitTestRect = backing()->compositedBounds(); 2555 } else 2556 #endif 2557 localHitTestRect = newTransformState->mappedQuad().enclosingBoundingBox(); 2558 2559 // Now do a hit test with the root layer shifted to be us. 2560 return hitTestLayer(this, containerLayer, request, result, localHitTestRect, localPoint, true, newTransformState.get(), zOffset); 2561 } 2562 2563 // Ensure our lists and 3d status are up-to-date. 2564 updateCompositingAndLayerListsIfNeeded(); 2565 update3DTransformedDescendantStatus(); 2566 2567 RefPtr<HitTestingTransformState> localTransformState; 2568 if (appliedTransform) { 2569 // We computed the correct state in the caller (above code), so just reference it. 2570 ASSERT(transformState); 2571 localTransformState = const_cast<HitTestingTransformState*>(transformState); 2572 } else if (transformState || m_has3DTransformedDescendant || preserves3D()) { 2573 // We need transform state for the first time, or to offset the container state, so create it here. 2574 localTransformState = createLocalTransformState(rootLayer, containerLayer, hitTestRect, hitTestPoint, transformState); 2575 } 2576 2577 // Check for hit test on backface if backface-visibility is 'hidden' 2578 if (localTransformState && renderer()->style()->backfaceVisibility() == BackfaceVisibilityHidden) { 2579 TransformationMatrix invertedMatrix = localTransformState->m_accumulatedTransform.inverse(); 2580 // If the z-vector of the matrix is negative, the back is facing towards the viewer. 2581 if (invertedMatrix.m33() < 0) 2582 return 0; 2583 } 2584 2585 RefPtr<HitTestingTransformState> unflattenedTransformState = localTransformState; 2586 if (localTransformState && !preserves3D()) { 2587 // Keep a copy of the pre-flattening state, for computing z-offsets for the container 2588 unflattenedTransformState = HitTestingTransformState::create(*localTransformState); 2589 // This layer is flattening, so flatten the state passed to descendants. 2590 localTransformState->flatten(); 2591 } 2592 2593 // Calculate the clip rects we should use. 2594 IntRect layerBounds; 2595 IntRect bgRect; 2596 IntRect fgRect; 2597 IntRect outlineRect; 2598 calculateRects(rootLayer, hitTestRect, layerBounds, bgRect, fgRect, outlineRect, useTemporaryClipRects); 2599 2600 // The following are used for keeping track of the z-depth of the hit point of 3d-transformed 2601 // descendants. 2602 double localZOffset = -numeric_limits<double>::infinity(); 2603 double* zOffsetForDescendantsPtr = 0; 2604 double* zOffsetForContentsPtr = 0; 2605 2606 bool depthSortDescendants = false; 2607 if (preserves3D()) { 2608 depthSortDescendants = true; 2609 // Our layers can depth-test with our container, so share the z depth pointer with the container, if it passed one down. 2610 zOffsetForDescendantsPtr = zOffset ? zOffset : &localZOffset; 2611 zOffsetForContentsPtr = zOffset ? zOffset : &localZOffset; 2612 } else if (m_has3DTransformedDescendant) { 2613 // Flattening layer with 3d children; use a local zOffset pointer to depth-test children and foreground. 2614 depthSortDescendants = true; 2615 zOffsetForDescendantsPtr = zOffset ? zOffset : &localZOffset; 2616 zOffsetForContentsPtr = zOffset ? zOffset : &localZOffset; 2617 } else if (zOffset) { 2618 zOffsetForDescendantsPtr = 0; 2619 // Container needs us to give back a z offset for the hit layer. 2620 zOffsetForContentsPtr = zOffset; 2621 } 2622 2623 // This variable tracks which layer the mouse ends up being inside. 2624 RenderLayer* candidateLayer = 0; 2625 2626 // Begin by walking our list of positive layers from highest z-index down to the lowest z-index. 2627 if (m_posZOrderList) { 2628 for (int i = m_posZOrderList->size() - 1; i >= 0; --i) { 2629 HitTestResult tempResult(result.point()); 2630 RenderLayer* hitLayer = m_posZOrderList->at(i)->hitTestLayer(rootLayer, this, request, tempResult, hitTestRect, hitTestPoint, false, localTransformState.get(), zOffsetForDescendantsPtr); 2631 if (isHitCandidate(hitLayer, depthSortDescendants, zOffset, unflattenedTransformState.get())) { 2632 result = tempResult; 2633 if (!depthSortDescendants) 2634 return hitLayer; 2635 2636 candidateLayer = hitLayer; 2637 } 2638 } 2639 } 2640 2641 // Now check our overflow objects. 2642 if (m_normalFlowList) { 2643 for (int i = m_normalFlowList->size() - 1; i >= 0; --i) { 2644 RenderLayer* currLayer = m_normalFlowList->at(i); 2645 HitTestResult tempResult(result.point()); 2646 RenderLayer* hitLayer = currLayer->hitTestLayer(rootLayer, this, request, tempResult, hitTestRect, hitTestPoint, false, localTransformState.get(), zOffsetForDescendantsPtr); 2647 if (isHitCandidate(hitLayer, depthSortDescendants, zOffset, unflattenedTransformState.get())) { 2648 result = tempResult; 2649 if (!depthSortDescendants) 2650 return hitLayer; 2651 2652 candidateLayer = hitLayer; 2653 } 2654 } 2655 } 2656 2657 // Next we want to see if the mouse pos is inside the child RenderObjects of the layer. 2658 if (fgRect.contains(hitTestPoint) && isSelfPaintingLayer()) { 2659 // Hit test with a temporary HitTestResult, because we only want to commit to 'result' if we know we're frontmost. 2660 HitTestResult tempResult(result.point()); 2661 if (hitTestContents(request, tempResult, layerBounds, hitTestPoint, HitTestDescendants) && 2662 isHitCandidate(this, false, zOffsetForContentsPtr, unflattenedTransformState.get())) { 2663 result = tempResult; 2664 if (!depthSortDescendants) 2665 return this; 2666 // Foreground can depth-sort with descendant layers, so keep this as a candidate. 2667 candidateLayer = this; 2668 } 2669 } 2670 2671 // Now check our negative z-index children. 2672 if (m_negZOrderList) { 2673 for (int i = m_negZOrderList->size() - 1; i >= 0; --i) { 2674 HitTestResult tempResult(result.point()); 2675 RenderLayer* hitLayer = m_negZOrderList->at(i)->hitTestLayer(rootLayer, this, request, tempResult, hitTestRect, hitTestPoint, false, localTransformState.get(), zOffsetForDescendantsPtr); 2676 if (isHitCandidate(hitLayer, depthSortDescendants, zOffset, unflattenedTransformState.get())) { 2677 result = tempResult; 2678 if (!depthSortDescendants) 2679 return hitLayer; 2680 2681 candidateLayer = hitLayer; 2682 } 2683 } 2684 } 2685 2686 // If we found a layer, return. Child layers, and foreground always render in front of background. 2687 if (candidateLayer) 2688 return candidateLayer; 2689 2690 if (bgRect.contains(hitTestPoint) && isSelfPaintingLayer()) { 2691 HitTestResult tempResult(result.point()); 2692 if (hitTestContents(request, tempResult, layerBounds, hitTestPoint, HitTestSelf) && 2693 isHitCandidate(this, false, zOffsetForContentsPtr, unflattenedTransformState.get())) { 2694 result = tempResult; 2695 return this; 2696 } 2697 } 2698 2699 return 0; 2700 } 2701 2702 bool RenderLayer::hitTestContents(const HitTestRequest& request, HitTestResult& result, const IntRect& layerBounds, const IntPoint& hitTestPoint, HitTestFilter hitTestFilter) const 2703 { 2704 if (!renderer()->hitTest(request, result, hitTestPoint, 2705 layerBounds.x() - renderBoxX(), 2706 layerBounds.y() - renderBoxY(), 2707 hitTestFilter)) { 2708 // It's wrong to set innerNode, but then claim that you didn't hit anything. 2709 ASSERT(!result.innerNode()); 2710 return false; 2711 } 2712 2713 // For positioned generated content, we might still not have a 2714 // node by the time we get to the layer level, since none of 2715 // the content in the layer has an element. So just walk up 2716 // the tree. 2717 if (!result.innerNode() || !result.innerNonSharedNode()) { 2718 Node* e = enclosingElement(); 2719 if (!result.innerNode()) 2720 result.setInnerNode(e); 2721 if (!result.innerNonSharedNode()) 2722 result.setInnerNonSharedNode(e); 2723 } 2724 2725 return true; 2726 } 2727 2728 void RenderLayer::updateClipRects(const RenderLayer* rootLayer) 2729 { 2730 if (m_clipRects) { 2731 ASSERT(rootLayer == m_clipRectsRoot); 2732 return; // We have the correct cached value. 2733 } 2734 2735 // For transformed layers, the root layer was shifted to be us, so there is no need to 2736 // examine the parent. We want to cache clip rects with us as the root. 2737 RenderLayer* parentLayer = rootLayer != this ? parent() : 0; 2738 if (parentLayer) 2739 parentLayer->updateClipRects(rootLayer); 2740 2741 ClipRects clipRects; 2742 calculateClipRects(rootLayer, clipRects, true); 2743 2744 if (parentLayer && parentLayer->clipRects() && clipRects == *parentLayer->clipRects()) 2745 m_clipRects = parentLayer->clipRects(); 2746 else 2747 m_clipRects = new (renderer()->renderArena()) ClipRects(clipRects); 2748 m_clipRects->ref(); 2749 #ifndef NDEBUG 2750 m_clipRectsRoot = rootLayer; 2751 #endif 2752 } 2753 2754 void RenderLayer::calculateClipRects(const RenderLayer* rootLayer, ClipRects& clipRects, bool useCached) const 2755 { 2756 if (!parent()) { 2757 // The root layer's clip rect is always infinite. 2758 clipRects.reset(ClipRects::infiniteRect()); 2759 return; 2760 } 2761 2762 // For transformed layers, the root layer was shifted to be us, so there is no need to 2763 // examine the parent. We want to cache clip rects with us as the root. 2764 RenderLayer* parentLayer = rootLayer != this ? parent() : 0; 2765 2766 // Ensure that our parent's clip has been calculated so that we can examine the values. 2767 if (parentLayer) { 2768 if (useCached && parentLayer->clipRects()) 2769 clipRects = *parentLayer->clipRects(); 2770 else 2771 parentLayer->calculateClipRects(rootLayer, clipRects); 2772 } 2773 else 2774 clipRects.reset(ClipRects::infiniteRect()); 2775 2776 // A fixed object is essentially the root of its containing block hierarchy, so when 2777 // we encounter such an object, we reset our clip rects to the fixedClipRect. 2778 if (renderer()->style()->position() == FixedPosition) { 2779 clipRects.setPosClipRect(clipRects.fixedClipRect()); 2780 clipRects.setOverflowClipRect(clipRects.fixedClipRect()); 2781 clipRects.setFixed(true); 2782 } 2783 else if (renderer()->style()->position() == RelativePosition) 2784 clipRects.setPosClipRect(clipRects.overflowClipRect()); 2785 else if (renderer()->style()->position() == AbsolutePosition) 2786 clipRects.setOverflowClipRect(clipRects.posClipRect()); 2787 2788 // Update the clip rects that will be passed to child layers. 2789 if (renderer()->hasOverflowClip() || renderer()->hasClip()) { 2790 // This layer establishes a clip of some kind. 2791 int x = 0; 2792 int y = 0; 2793 convertToLayerCoords(rootLayer, x, y); 2794 RenderView* view = renderer()->view(); 2795 ASSERT(view); 2796 if (view && clipRects.fixed() && rootLayer->renderer() == view) { 2797 x -= view->frameView()->scrollX(); 2798 y -= view->frameView()->scrollY(); 2799 } 2800 2801 if (renderer()->hasOverflowClip()) { 2802 IntRect newOverflowClip = toRenderBox(renderer())->overflowClipRect(x, y); 2803 clipRects.setOverflowClipRect(intersection(newOverflowClip, clipRects.overflowClipRect())); 2804 if (renderer()->isPositioned() || renderer()->isRelPositioned()) 2805 clipRects.setPosClipRect(intersection(newOverflowClip, clipRects.posClipRect())); 2806 } 2807 if (renderer()->hasClip()) { 2808 IntRect newPosClip = toRenderBox(renderer())->clipRect(x, y); 2809 clipRects.setPosClipRect(intersection(newPosClip, clipRects.posClipRect())); 2810 clipRects.setOverflowClipRect(intersection(newPosClip, clipRects.overflowClipRect())); 2811 clipRects.setFixedClipRect(intersection(newPosClip, clipRects.fixedClipRect())); 2812 } 2813 } 2814 } 2815 2816 void RenderLayer::parentClipRects(const RenderLayer* rootLayer, ClipRects& clipRects, bool temporaryClipRects) const 2817 { 2818 ASSERT(parent()); 2819 if (temporaryClipRects) { 2820 parent()->calculateClipRects(rootLayer, clipRects); 2821 return; 2822 } 2823 2824 parent()->updateClipRects(rootLayer); 2825 clipRects = *parent()->clipRects(); 2826 } 2827 2828 IntRect RenderLayer::backgroundClipRect(const RenderLayer* rootLayer, bool temporaryClipRects) const 2829 { 2830 IntRect backgroundRect; 2831 if (parent()) { 2832 ClipRects parentRects; 2833 parentClipRects(rootLayer, parentRects, temporaryClipRects); 2834 backgroundRect = renderer()->style()->position() == FixedPosition ? parentRects.fixedClipRect() : 2835 (renderer()->isPositioned() ? parentRects.posClipRect() : 2836 parentRects.overflowClipRect()); 2837 RenderView* view = renderer()->view(); 2838 ASSERT(view); 2839 if (view && parentRects.fixed() && rootLayer->renderer() == view) 2840 backgroundRect.move(view->frameView()->scrollX(), view->frameView()->scrollY()); 2841 } 2842 return backgroundRect; 2843 } 2844 2845 void RenderLayer::calculateRects(const RenderLayer* rootLayer, const IntRect& paintDirtyRect, IntRect& layerBounds, 2846 IntRect& backgroundRect, IntRect& foregroundRect, IntRect& outlineRect, bool temporaryClipRects) const 2847 { 2848 if (rootLayer != this && parent()) { 2849 backgroundRect = backgroundClipRect(rootLayer, temporaryClipRects); 2850 backgroundRect.intersect(paintDirtyRect); 2851 } else 2852 backgroundRect = paintDirtyRect; 2853 2854 foregroundRect = backgroundRect; 2855 outlineRect = backgroundRect; 2856 2857 int x = 0; 2858 int y = 0; 2859 convertToLayerCoords(rootLayer, x, y); 2860 layerBounds = IntRect(x, y, width(), height()); 2861 2862 // Update the clip rects that will be passed to child layers. 2863 if (renderer()->hasOverflowClip() || renderer()->hasClip()) { 2864 // This layer establishes a clip of some kind. 2865 if (renderer()->hasOverflowClip()) 2866 foregroundRect.intersect(toRenderBox(renderer())->overflowClipRect(x, y)); 2867 if (renderer()->hasClip()) { 2868 // Clip applies to *us* as well, so go ahead and update the damageRect. 2869 IntRect newPosClip = toRenderBox(renderer())->clipRect(x, y); 2870 backgroundRect.intersect(newPosClip); 2871 foregroundRect.intersect(newPosClip); 2872 outlineRect.intersect(newPosClip); 2873 } 2874 2875 // If we establish a clip at all, then go ahead and make sure our background 2876 // rect is intersected with our layer's bounds. 2877 if (ShadowData* boxShadow = renderer()->style()->boxShadow()) { 2878 IntRect overflow = layerBounds; 2879 do { 2880 if (boxShadow->style == Normal) { 2881 IntRect shadowRect = layerBounds; 2882 shadowRect.move(boxShadow->x, boxShadow->y); 2883 shadowRect.inflate(boxShadow->blur + boxShadow->spread); 2884 overflow.unite(shadowRect); 2885 } 2886 2887 boxShadow = boxShadow->next; 2888 } while (boxShadow); 2889 backgroundRect.intersect(overflow); 2890 } else 2891 backgroundRect.intersect(layerBounds); 2892 } 2893 } 2894 2895 IntRect RenderLayer::childrenClipRect() const 2896 { 2897 RenderLayer* rootLayer = renderer()->view()->layer(); 2898 RenderLayer* clippingRootLayer = clippingRoot(); 2899 IntRect layerBounds, backgroundRect, foregroundRect, outlineRect; 2900 calculateRects(clippingRootLayer, rootLayer->boundingBox(rootLayer), layerBounds, backgroundRect, foregroundRect, outlineRect); 2901 return clippingRootLayer->renderer()->localToAbsoluteQuad(FloatQuad(foregroundRect)).enclosingBoundingBox(); 2902 } 2903 2904 IntRect RenderLayer::selfClipRect() const 2905 { 2906 RenderLayer* rootLayer = renderer()->view()->layer(); 2907 RenderLayer* clippingRootLayer = clippingRoot(); 2908 IntRect layerBounds, backgroundRect, foregroundRect, outlineRect; 2909 calculateRects(clippingRootLayer, rootLayer->boundingBox(rootLayer), layerBounds, backgroundRect, foregroundRect, outlineRect); 2910 return clippingRootLayer->renderer()->localToAbsoluteQuad(FloatQuad(backgroundRect)).enclosingBoundingBox(); 2911 } 2912 2913 void RenderLayer::addBlockSelectionGapsBounds(const IntRect& bounds) 2914 { 2915 m_blockSelectionGapsBounds.unite(bounds); 2916 } 2917 2918 void RenderLayer::clearBlockSelectionGapsBounds() 2919 { 2920 m_blockSelectionGapsBounds = IntRect(); 2921 for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) 2922 child->clearBlockSelectionGapsBounds(); 2923 } 2924 2925 void RenderLayer::repaintBlockSelectionGaps() 2926 { 2927 for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) 2928 child->repaintBlockSelectionGaps(); 2929 2930 if (m_blockSelectionGapsBounds.isEmpty()) 2931 return; 2932 2933 IntRect rect = m_blockSelectionGapsBounds; 2934 rect.move(-scrolledContentOffset()); 2935 if (renderer()->hasOverflowClip()) 2936 rect.intersect(toRenderBox(renderer())->overflowClipRect(0, 0)); 2937 if (renderer()->hasClip()) 2938 rect.intersect(toRenderBox(renderer())->clipRect(0, 0)); 2939 if (!rect.isEmpty()) 2940 renderer()->repaintRectangle(rect); 2941 } 2942 2943 bool RenderLayer::intersectsDamageRect(const IntRect& layerBounds, const IntRect& damageRect, const RenderLayer* rootLayer) const 2944 { 2945 // Always examine the canvas and the root. 2946 // FIXME: Could eliminate the isRoot() check if we fix background painting so that the RenderView 2947 // paints the root's background. 2948 if (renderer()->isRenderView() || renderer()->isRoot()) 2949 return true; 2950 2951 // If we aren't an inline flow, and our layer bounds do intersect the damage rect, then we 2952 // can go ahead and return true. 2953 RenderView* view = renderer()->view(); 2954 ASSERT(view); 2955 if (view && !renderer()->isRenderInline()) { 2956 IntRect b = layerBounds; 2957 b.inflate(view->maximalOutlineSize()); 2958 if (b.intersects(damageRect)) 2959 return true; 2960 } 2961 2962 // Otherwise we need to compute the bounding box of this single layer and see if it intersects 2963 // the damage rect. 2964 return boundingBox(rootLayer).intersects(damageRect); 2965 } 2966 2967 IntRect RenderLayer::localBoundingBox() const 2968 { 2969 // There are three special cases we need to consider. 2970 // (1) Inline Flows. For inline flows we will create a bounding box that fully encompasses all of the lines occupied by the 2971 // inline. In other words, if some <span> wraps to three lines, we'll create a bounding box that fully encloses the 2972 // line boxes of all three lines (including overflow on those lines). 2973 // (2) Left/Top Overflow. The width/height of layers already includes right/bottom overflow. However, in the case of left/top 2974 // overflow, we have to create a bounding box that will extend to include this overflow. 2975 // (3) Floats. When a layer has overhanging floats that it paints, we need to make sure to include these overhanging floats 2976 // as part of our bounding box. We do this because we are the responsible layer for both hit testing and painting those 2977 // floats. 2978 IntRect result; 2979 if (renderer()->isRenderInline()) { 2980 // Go from our first line box to our last line box. 2981 RenderInline* inlineFlow = toRenderInline(renderer()); 2982 InlineFlowBox* firstBox = inlineFlow->firstLineBox(); 2983 if (!firstBox) 2984 return result; 2985 int top = firstBox->topVisibleOverflow(); 2986 int bottom = inlineFlow->lastLineBox()->bottomVisibleOverflow(); 2987 int left = firstBox->x(); 2988 for (InlineRunBox* curr = firstBox->nextLineBox(); curr; curr = curr->nextLineBox()) 2989 left = min(left, curr->x()); 2990 result = IntRect(left, top, width(), bottom - top); 2991 } else if (renderer()->isTableRow()) { 2992 // Our bounding box is just the union of all of our cells' border/overflow rects. 2993 for (RenderObject* child = renderer()->firstChild(); child; child = child->nextSibling()) { 2994 if (child->isTableCell()) { 2995 IntRect bbox = toRenderBox(child)->borderBoxRect(); 2996 result.unite(bbox); 2997 IntRect overflowRect = renderBox()->visibleOverflowRect(); 2998 if (bbox != overflowRect) 2999 result.unite(overflowRect); 3000 } 3001 } 3002 } else { 3003 RenderBox* box = renderBox(); 3004 ASSERT(box); 3005 if (box->hasMask()) 3006 result = box->maskClipRect(); 3007 else { 3008 IntRect bbox = box->borderBoxRect(); 3009 result = bbox; 3010 IntRect overflowRect = box->visibleOverflowRect(); 3011 if (bbox != overflowRect) 3012 result.unite(overflowRect); 3013 } 3014 } 3015 3016 RenderView* view = renderer()->view(); 3017 ASSERT(view); 3018 if (view) 3019 result.inflate(view->maximalOutlineSize()); // Used to apply a fudge factor to dirty-rect checks on blocks/tables. 3020 3021 return result; 3022 } 3023 3024 IntRect RenderLayer::boundingBox(const RenderLayer* ancestorLayer) const 3025 { 3026 IntRect result = localBoundingBox(); 3027 3028 int deltaX = 0, deltaY = 0; 3029 convertToLayerCoords(ancestorLayer, deltaX, deltaY); 3030 result.move(deltaX, deltaY); 3031 return result; 3032 } 3033 3034 IntRect RenderLayer::absoluteBoundingBox() const 3035 { 3036 return boundingBox(root()); 3037 } 3038 3039 void RenderLayer::clearClipRectsIncludingDescendants() 3040 { 3041 if (!m_clipRects) 3042 return; 3043 3044 clearClipRects(); 3045 3046 for (RenderLayer* l = firstChild(); l; l = l->nextSibling()) 3047 l->clearClipRectsIncludingDescendants(); 3048 } 3049 3050 void RenderLayer::clearClipRects() 3051 { 3052 if (m_clipRects) { 3053 m_clipRects->deref(renderer()->renderArena()); 3054 m_clipRects = 0; 3055 #ifndef NDEBUG 3056 m_clipRectsRoot = 0; 3057 #endif 3058 } 3059 } 3060 3061 #if USE(ACCELERATED_COMPOSITING) 3062 RenderLayerBacking* RenderLayer::ensureBacking() 3063 { 3064 if (!m_backing) 3065 m_backing.set(new RenderLayerBacking(this)); 3066 return m_backing.get(); 3067 } 3068 3069 void RenderLayer::clearBacking() 3070 { 3071 m_backing.clear(); 3072 } 3073 3074 bool RenderLayer::hasCompositedMask() const 3075 { 3076 return m_backing && m_backing->hasMaskLayer(); 3077 } 3078 #endif 3079 3080 void RenderLayer::setParent(RenderLayer* parent) 3081 { 3082 if (parent == m_parent) 3083 return; 3084 3085 #if USE(ACCELERATED_COMPOSITING) 3086 if (m_parent && !renderer()->documentBeingDestroyed()) 3087 compositor()->layerWillBeRemoved(m_parent, this); 3088 #endif 3089 3090 m_parent = parent; 3091 3092 #if USE(ACCELERATED_COMPOSITING) 3093 if (m_parent && !renderer()->documentBeingDestroyed()) 3094 compositor()->layerWasAdded(m_parent, this); 3095 #endif 3096 } 3097 3098 static RenderObject* commonAncestor(RenderObject* obj1, RenderObject* obj2) 3099 { 3100 if (!obj1 || !obj2) 3101 return 0; 3102 3103 for (RenderObject* currObj1 = obj1; currObj1; currObj1 = currObj1->hoverAncestor()) 3104 for (RenderObject* currObj2 = obj2; currObj2; currObj2 = currObj2->hoverAncestor()) 3105 if (currObj1 == currObj2) 3106 return currObj1; 3107 3108 return 0; 3109 } 3110 3111 void RenderLayer::updateHoverActiveState(const HitTestRequest& request, HitTestResult& result) 3112 { 3113 // We don't update :hover/:active state when the result is marked as readOnly. 3114 if (request.readOnly()) 3115 return; 3116 3117 Document* doc = renderer()->document(); 3118 3119 Node* activeNode = doc->activeNode(); 3120 if (activeNode && !request.active()) { 3121 // We are clearing the :active chain because the mouse has been released. 3122 for (RenderObject* curr = activeNode->renderer(); curr; curr = curr->parent()) { 3123 if (curr->node() && !curr->isText()) 3124 curr->node()->setInActiveChain(false); 3125 } 3126 doc->setActiveNode(0); 3127 } else { 3128 Node* newActiveNode = result.innerNode(); 3129 if (!activeNode && newActiveNode && request.active()) { 3130 // We are setting the :active chain and freezing it. If future moves happen, they 3131 // will need to reference this chain. 3132 for (RenderObject* curr = newActiveNode->renderer(); curr; curr = curr->parent()) { 3133 if (curr->node() && !curr->isText()) { 3134 curr->node()->setInActiveChain(true); 3135 } 3136 } 3137 doc->setActiveNode(newActiveNode); 3138 } 3139 } 3140 3141 // If the mouse is down and if this is a mouse move event, we want to restrict changes in 3142 // :hover/:active to only apply to elements that are in the :active chain that we froze 3143 // at the time the mouse went down. 3144 bool mustBeInActiveChain = request.active() && request.mouseMove(); 3145 3146 // Check to see if the hovered node has changed. If not, then we don't need to 3147 // do anything. 3148 RefPtr<Node> oldHoverNode = doc->hoverNode(); 3149 Node* newHoverNode = result.innerNode(); 3150 3151 // Update our current hover node. 3152 doc->setHoverNode(newHoverNode); 3153 3154 // We have two different objects. Fetch their renderers. 3155 RenderObject* oldHoverObj = oldHoverNode ? oldHoverNode->renderer() : 0; 3156 RenderObject* newHoverObj = newHoverNode ? newHoverNode->renderer() : 0; 3157 3158 // Locate the common ancestor render object for the two renderers. 3159 RenderObject* ancestor = commonAncestor(oldHoverObj, newHoverObj); 3160 3161 if (oldHoverObj != newHoverObj) { 3162 // The old hover path only needs to be cleared up to (and not including) the common ancestor; 3163 for (RenderObject* curr = oldHoverObj; curr && curr != ancestor; curr = curr->hoverAncestor()) { 3164 if (curr->node() && !curr->isText() && (!mustBeInActiveChain || curr->node()->inActiveChain())) { 3165 curr->node()->setActive(false); 3166 curr->node()->setHovered(false); 3167 } 3168 } 3169 } 3170 3171 // Now set the hover state for our new object up to the root. 3172 for (RenderObject* curr = newHoverObj; curr; curr = curr->hoverAncestor()) { 3173 if (curr->node() && !curr->isText() && (!mustBeInActiveChain || curr->node()->inActiveChain())) { 3174 curr->node()->setActive(request.active()); 3175 curr->node()->setHovered(true); 3176 } 3177 } 3178 } 3179 3180 // Helper for the sorting of layers by z-index. 3181 static inline bool compareZIndex(RenderLayer* first, RenderLayer* second) 3182 { 3183 return first->zIndex() < second->zIndex(); 3184 } 3185 3186 void RenderLayer::dirtyZOrderLists() 3187 { 3188 if (m_posZOrderList) 3189 m_posZOrderList->clear(); 3190 if (m_negZOrderList) 3191 m_negZOrderList->clear(); 3192 m_zOrderListsDirty = true; 3193 3194 #if USE(ACCELERATED_COMPOSITING) 3195 if (!renderer()->documentBeingDestroyed()) 3196 compositor()->setCompositingLayersNeedRebuild(); 3197 #endif 3198 } 3199 3200 void RenderLayer::dirtyStackingContextZOrderLists() 3201 { 3202 RenderLayer* sc = stackingContext(); 3203 if (sc) 3204 sc->dirtyZOrderLists(); 3205 } 3206 3207 void RenderLayer::dirtyNormalFlowList() 3208 { 3209 if (m_normalFlowList) 3210 m_normalFlowList->clear(); 3211 m_normalFlowListDirty = true; 3212 3213 #if USE(ACCELERATED_COMPOSITING) 3214 if (!renderer()->documentBeingDestroyed()) 3215 compositor()->setCompositingLayersNeedRebuild(); 3216 #endif 3217 } 3218 3219 void RenderLayer::updateZOrderLists() 3220 { 3221 if (!isStackingContext() || !m_zOrderListsDirty) 3222 return; 3223 3224 for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) 3225 if (!m_reflection || reflectionLayer() != child) 3226 child->collectLayers(m_posZOrderList, m_negZOrderList); 3227 3228 // Sort the two lists. 3229 if (m_posZOrderList) 3230 std::stable_sort(m_posZOrderList->begin(), m_posZOrderList->end(), compareZIndex); 3231 3232 if (m_negZOrderList) 3233 std::stable_sort(m_negZOrderList->begin(), m_negZOrderList->end(), compareZIndex); 3234 3235 m_zOrderListsDirty = false; 3236 } 3237 3238 void RenderLayer::updateNormalFlowList() 3239 { 3240 if (!m_normalFlowListDirty) 3241 return; 3242 3243 for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) { 3244 // Ignore non-overflow layers and reflections. 3245 if (child->isNormalFlowOnly() && (!m_reflection || reflectionLayer() != child)) { 3246 if (!m_normalFlowList) 3247 m_normalFlowList = new Vector<RenderLayer*>; 3248 m_normalFlowList->append(child); 3249 } 3250 } 3251 3252 m_normalFlowListDirty = false; 3253 } 3254 3255 void RenderLayer::collectLayers(Vector<RenderLayer*>*& posBuffer, Vector<RenderLayer*>*& negBuffer) 3256 { 3257 updateVisibilityStatus(); 3258 3259 // Overflow layers are just painted by their enclosing layers, so they don't get put in zorder lists. 3260 if ((m_hasVisibleContent || (m_hasVisibleDescendant && isStackingContext())) && !isNormalFlowOnly()) { 3261 // Determine which buffer the child should be in. 3262 Vector<RenderLayer*>*& buffer = (zIndex() >= 0) ? posBuffer : negBuffer; 3263 3264 // Create the buffer if it doesn't exist yet. 3265 if (!buffer) 3266 buffer = new Vector<RenderLayer*>; 3267 3268 // Append ourselves at the end of the appropriate buffer. 3269 buffer->append(this); 3270 } 3271 3272 // Recur into our children to collect more layers, but only if we don't establish 3273 // a stacking context. 3274 if (m_hasVisibleDescendant && !isStackingContext()) { 3275 for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) { 3276 // Ignore reflections. 3277 if (!m_reflection || reflectionLayer() != child) 3278 child->collectLayers(posBuffer, negBuffer); 3279 } 3280 } 3281 } 3282 3283 void RenderLayer::updateLayerListsIfNeeded() 3284 { 3285 updateZOrderLists(); 3286 updateNormalFlowList(); 3287 } 3288 3289 void RenderLayer::updateCompositingAndLayerListsIfNeeded() 3290 { 3291 #if USE(ACCELERATED_COMPOSITING) 3292 if (compositor()->inCompositingMode()) { 3293 if ((isStackingContext() && m_zOrderListsDirty) || m_normalFlowListDirty) 3294 compositor()->updateCompositingLayers(CompositingUpdateOnPaitingOrHitTest, this); 3295 return; 3296 } 3297 #endif 3298 updateLayerListsIfNeeded(); 3299 } 3300 3301 void RenderLayer::repaintIncludingDescendants() 3302 { 3303 renderer()->repaint(); 3304 for (RenderLayer* curr = firstChild(); curr; curr = curr->nextSibling()) 3305 curr->repaintIncludingDescendants(); 3306 } 3307 3308 #if USE(ACCELERATED_COMPOSITING) 3309 void RenderLayer::setBackingNeedsRepaint() 3310 { 3311 ASSERT(isComposited()); 3312 if (backing()->paintingGoesToWindow()) { 3313 // If we're trying to repaint the placeholder document layer, propagate the 3314 // repaint to the native view system. 3315 RenderView* view = renderer()->view(); 3316 if (view) 3317 view->repaintViewRectangle(absoluteBoundingBox()); 3318 } else 3319 backing()->setContentsNeedDisplay(); 3320 } 3321 3322 void RenderLayer::setBackingNeedsRepaintInRect(const IntRect& r) 3323 { 3324 ASSERT(isComposited()); 3325 if (backing()->paintingGoesToWindow()) { 3326 // If we're trying to repaint the placeholder document layer, propagate the 3327 // repaint to the native view system. 3328 IntRect absRect(r); 3329 int x = 0; 3330 int y = 0; 3331 convertToLayerCoords(root(), x, y); 3332 absRect.move(x, y); 3333 3334 RenderView* view = renderer()->view(); 3335 if (view) 3336 view->repaintViewRectangle(absRect); 3337 } else 3338 backing()->setContentsNeedDisplayInRect(r); 3339 } 3340 3341 // Since we're only painting non-composited layers, we know that they all share the same repaintContainer. 3342 void RenderLayer::repaintIncludingNonCompositingDescendants(RenderBoxModelObject* repaintContainer) 3343 { 3344 renderer()->repaintUsingContainer(repaintContainer, renderer()->clippedOverflowRectForRepaint(repaintContainer)); 3345 3346 for (RenderLayer* curr = firstChild(); curr; curr = curr->nextSibling()) { 3347 if (!curr->isComposited()) 3348 curr->repaintIncludingNonCompositingDescendants(repaintContainer); 3349 } 3350 } 3351 #endif 3352 3353 bool RenderLayer::shouldBeNormalFlowOnly() const 3354 { 3355 return (renderer()->hasOverflowClip() || renderer()->hasReflection() || renderer()->hasMask() || renderer()->isVideo() || renderer()->isEmbeddedObject()) && 3356 !renderer()->isPositioned() && 3357 !renderer()->isRelPositioned() && 3358 !renderer()->hasTransform() && 3359 !isTransparent(); 3360 } 3361 3362 bool RenderLayer::isSelfPaintingLayer() const 3363 { 3364 return !isNormalFlowOnly() || renderer()->hasReflection() || renderer()->hasMask() || renderer()->isTableRow() || renderer()->isVideo() || renderer()->isEmbeddedObject(); 3365 } 3366 3367 void RenderLayer::styleChanged(StyleDifference diff, const RenderStyle*) 3368 { 3369 bool isNormalFlowOnly = shouldBeNormalFlowOnly(); 3370 if (isNormalFlowOnly != m_isNormalFlowOnly) { 3371 m_isNormalFlowOnly = isNormalFlowOnly; 3372 RenderLayer* p = parent(); 3373 if (p) 3374 p->dirtyNormalFlowList(); 3375 dirtyStackingContextZOrderLists(); 3376 } 3377 3378 if (renderer()->style()->overflowX() == OMARQUEE && renderer()->style()->marqueeBehavior() != MNONE && renderer()->isBox()) { 3379 if (!m_marquee) 3380 m_marquee = new RenderMarquee(this); 3381 m_marquee->updateMarqueeStyle(); 3382 } 3383 else if (m_marquee) { 3384 delete m_marquee; 3385 m_marquee = 0; 3386 } 3387 3388 if (!hasReflection() && m_reflection) 3389 removeReflection(); 3390 else if (hasReflection()) { 3391 if (!m_reflection) 3392 createReflection(); 3393 updateReflectionStyle(); 3394 } 3395 3396 // FIXME: Need to detect a swap from custom to native scrollbars (and vice versa). 3397 if (m_hBar) 3398 m_hBar->styleChanged(); 3399 if (m_vBar) 3400 m_vBar->styleChanged(); 3401 3402 updateScrollCornerStyle(); 3403 updateResizerStyle(); 3404 3405 #if USE(ACCELERATED_COMPOSITING) 3406 updateTransform(); 3407 3408 if (compositor()->updateLayerCompositingState(this)) 3409 compositor()->setCompositingLayersNeedRebuild(); 3410 else if (m_backing) 3411 m_backing->updateGraphicsLayerGeometry(); 3412 3413 if (m_backing && diff >= StyleDifferenceRepaint) 3414 m_backing->setContentsNeedDisplay(); 3415 #else 3416 UNUSED_PARAM(diff); 3417 #endif 3418 } 3419 3420 void RenderLayer::updateScrollCornerStyle() 3421 { 3422 RenderObject* actualRenderer = renderer()->node() ? renderer()->node()->shadowAncestorNode()->renderer() : renderer(); 3423 RefPtr<RenderStyle> corner = renderer()->hasOverflowClip() ? actualRenderer->getUncachedPseudoStyle(SCROLLBAR_CORNER, actualRenderer->style()) : 0; 3424 if (corner) { 3425 if (!m_scrollCorner) { 3426 m_scrollCorner = new (renderer()->renderArena()) RenderScrollbarPart(renderer()->document()); 3427 m_scrollCorner->setParent(renderer()); 3428 } 3429 m_scrollCorner->setStyle(corner.release()); 3430 } else if (m_scrollCorner) { 3431 m_scrollCorner->destroy(); 3432 m_scrollCorner = 0; 3433 } 3434 } 3435 3436 void RenderLayer::updateResizerStyle() 3437 { 3438 RenderObject* actualRenderer = renderer()->node() ? renderer()->node()->shadowAncestorNode()->renderer() : renderer(); 3439 RefPtr<RenderStyle> resizer = renderer()->hasOverflowClip() ? actualRenderer->getUncachedPseudoStyle(RESIZER, actualRenderer->style()) : 0; 3440 if (resizer) { 3441 if (!m_resizer) { 3442 m_resizer = new (renderer()->renderArena()) RenderScrollbarPart(renderer()->document()); 3443 m_resizer->setParent(renderer()); 3444 } 3445 m_resizer->setStyle(resizer.release()); 3446 } else if (m_resizer) { 3447 m_resizer->destroy(); 3448 m_resizer = 0; 3449 } 3450 } 3451 3452 RenderLayer* RenderLayer::reflectionLayer() const 3453 { 3454 return m_reflection ? m_reflection->layer() : 0; 3455 } 3456 3457 void RenderLayer::createReflection() 3458 { 3459 ASSERT(!m_reflection); 3460 m_reflection = new (renderer()->renderArena()) RenderReplica(renderer()->document()); 3461 m_reflection->setParent(renderer()); // We create a 1-way connection. 3462 } 3463 3464 void RenderLayer::removeReflection() 3465 { 3466 if (!m_reflection->documentBeingDestroyed()) 3467 m_reflection->removeLayers(this); 3468 3469 m_reflection->setParent(0); 3470 m_reflection->destroy(); 3471 m_reflection = 0; 3472 } 3473 3474 void RenderLayer::updateReflectionStyle() 3475 { 3476 RefPtr<RenderStyle> newStyle = RenderStyle::create(); 3477 newStyle->inheritFrom(renderer()->style()); 3478 3479 // Map in our transform. 3480 TransformOperations transform; 3481 switch (renderer()->style()->boxReflect()->direction()) { 3482 case ReflectionBelow: 3483 transform.operations().append(TranslateTransformOperation::create(Length(0, Fixed), Length(100., Percent), TransformOperation::TRANSLATE)); 3484 transform.operations().append(TranslateTransformOperation::create(Length(0, Fixed), renderer()->style()->boxReflect()->offset(), TransformOperation::TRANSLATE)); 3485 transform.operations().append(ScaleTransformOperation::create(1.0, -1.0, ScaleTransformOperation::SCALE)); 3486 break; 3487 case ReflectionAbove: 3488 transform.operations().append(ScaleTransformOperation::create(1.0, -1.0, ScaleTransformOperation::SCALE)); 3489 transform.operations().append(TranslateTransformOperation::create(Length(0, Fixed), Length(100., Percent), TransformOperation::TRANSLATE)); 3490 transform.operations().append(TranslateTransformOperation::create(Length(0, Fixed), renderer()->style()->boxReflect()->offset(), TransformOperation::TRANSLATE)); 3491 break; 3492 case ReflectionRight: 3493 transform.operations().append(TranslateTransformOperation::create(Length(100., Percent), Length(0, Fixed), TransformOperation::TRANSLATE)); 3494 transform.operations().append(TranslateTransformOperation::create(renderer()->style()->boxReflect()->offset(), Length(0, Fixed), TransformOperation::TRANSLATE)); 3495 transform.operations().append(ScaleTransformOperation::create(-1.0, 1.0, ScaleTransformOperation::SCALE)); 3496 break; 3497 case ReflectionLeft: 3498 transform.operations().append(ScaleTransformOperation::create(-1.0, 1.0, ScaleTransformOperation::SCALE)); 3499 transform.operations().append(TranslateTransformOperation::create(Length(100., Percent), Length(0, Fixed), TransformOperation::TRANSLATE)); 3500 transform.operations().append(TranslateTransformOperation::create(renderer()->style()->boxReflect()->offset(), Length(0, Fixed), TransformOperation::TRANSLATE)); 3501 break; 3502 } 3503 newStyle->setTransform(transform); 3504 3505 // Map in our mask. 3506 newStyle->setMaskBoxImage(renderer()->style()->boxReflect()->mask()); 3507 3508 m_reflection->setStyle(newStyle.release()); 3509 } 3510 3511 } // namespace WebCore 3512 3513 #ifndef NDEBUG 3514 void showLayerTree(const WebCore::RenderLayer* layer) 3515 { 3516 if (!layer) 3517 return; 3518 3519 if (WebCore::Frame* frame = layer->renderer()->document()->frame()) { 3520 WebCore::String output = externalRepresentation(frame, WebCore::RenderAsTextShowAllLayers | WebCore::RenderAsTextShowLayerNesting | WebCore::RenderAsTextShowCompositedLayers); 3521 fprintf(stderr, "%s\n", output.utf8().data()); 3522 } 3523 } 3524 #endif 3525