Home | History | Annotate | Download | only in rendering
      1 /*
      2  * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012 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 "core/rendering/RenderLayer.h"
     46 
     47 #include "core/css/PseudoStyleRequest.h"
     48 #include "core/dom/shadow/ShadowRoot.h"
     49 #include "core/editing/FrameSelection.h"
     50 #include "core/html/HTMLFrameOwnerElement.h"
     51 #include "core/inspector/InspectorInstrumentation.h"
     52 #include "core/page/EventHandler.h"
     53 #include "core/page/FocusController.h"
     54 #include "core/frame/Frame.h"
     55 #include "core/frame/FrameView.h"
     56 #include "core/page/Page.h"
     57 #include "core/page/scrolling/ScrollingCoordinator.h"
     58 #include "core/rendering/CompositedLayerMapping.h"
     59 #include "core/rendering/RenderGeometryMap.h"
     60 #include "core/rendering/RenderLayerCompositor.h"
     61 #include "core/rendering/RenderScrollbar.h"
     62 #include "core/rendering/RenderScrollbarPart.h"
     63 #include "core/rendering/RenderView.h"
     64 #include "platform/PlatformGestureEvent.h"
     65 #include "platform/PlatformMouseEvent.h"
     66 #include "platform/graphics/GraphicsContextStateSaver.h"
     67 #include "platform/graphics/GraphicsLayer.h"
     68 #include "platform/scroll/ScrollAnimator.h"
     69 #include "platform/scroll/ScrollbarTheme.h"
     70 #include "public/platform/Platform.h"
     71 
     72 namespace WebCore {
     73 
     74 const int ResizerControlExpandRatioForTouch = 2;
     75 
     76 RenderLayerScrollableArea::RenderLayerScrollableArea(RenderBox* box)
     77     : m_box(box)
     78     , m_inResizeMode(false)
     79     , m_scrollDimensionsDirty(true)
     80     , m_inOverflowRelayout(false)
     81     , m_needsCompositedScrolling(false)
     82     , m_willUseCompositedScrollingHasBeenRecorded(false)
     83     , m_isScrollableAreaHasBeenRecorded(false)
     84     , m_forceNeedsCompositedScrolling(DoNotForceCompositedScrolling)
     85     , m_scrollCorner(0)
     86     , m_resizer(0)
     87 {
     88     ScrollableArea::setConstrainsScrollingToContentEdge(false);
     89 
     90     Node* node = m_box->node();
     91     if (node && node->isElementNode()) {
     92         // We save and restore only the scrollOffset as the other scroll values are recalculated.
     93         Element* element = toElement(node);
     94         m_scrollOffset = element->savedLayerScrollOffset();
     95         if (!m_scrollOffset.isZero())
     96             scrollAnimator()->setCurrentPosition(FloatPoint(m_scrollOffset.width(), m_scrollOffset.height()));
     97         element->setSavedLayerScrollOffset(IntSize());
     98     }
     99 
    100     updateResizerAreaSet();
    101 }
    102 
    103 RenderLayerScrollableArea::~RenderLayerScrollableArea()
    104 {
    105     if (inResizeMode() && !m_box->documentBeingDestroyed()) {
    106         if (Frame* frame = m_box->frame())
    107             frame->eventHandler().resizeScrollableAreaDestroyed();
    108     }
    109 
    110     if (Frame* frame = m_box->frame()) {
    111         if (FrameView* frameView = frame->view()) {
    112             frameView->removeScrollableArea(this);
    113         }
    114     }
    115 
    116     if (m_box->frame() && m_box->frame()->page()) {
    117         if (ScrollingCoordinator* scrollingCoordinator = m_box->frame()->page()->scrollingCoordinator())
    118             scrollingCoordinator->willDestroyScrollableArea(this);
    119     }
    120 
    121     if (!m_box->documentBeingDestroyed()) {
    122         Node* node = m_box->node();
    123         if (node && node->isElementNode())
    124             toElement(node)->setSavedLayerScrollOffset(m_scrollOffset);
    125     }
    126 
    127     if (Frame* frame = m_box->frame()) {
    128         if (FrameView* frameView = frame->view())
    129             frameView->removeResizerArea(m_box);
    130     }
    131 
    132     destroyScrollbar(HorizontalScrollbar);
    133     destroyScrollbar(VerticalScrollbar);
    134 
    135     if (m_scrollCorner)
    136         m_scrollCorner->destroy();
    137     if (m_resizer)
    138         m_resizer->destroy();
    139 }
    140 
    141 ScrollableArea* RenderLayerScrollableArea::enclosingScrollableArea() const
    142 {
    143     if (RenderBox* enclosingScrollableBox = m_box->enclosingScrollableBox())
    144         return enclosingScrollableBox->layer()->scrollableArea();
    145 
    146     // FIXME: We should return the frame view here (or possibly an ancestor frame view,
    147     // if the frame view isn't scrollable.
    148     return 0;
    149 }
    150 
    151 GraphicsLayer* RenderLayerScrollableArea::layerForScrolling() const
    152 {
    153     return m_box->hasCompositedLayerMapping() ? m_box->compositedLayerMapping()->scrollingContentsLayer() : 0;
    154 }
    155 
    156 GraphicsLayer* RenderLayerScrollableArea::layerForHorizontalScrollbar() const
    157 {
    158     return m_box->hasCompositedLayerMapping() ? m_box->compositedLayerMapping()->layerForHorizontalScrollbar() : 0;
    159 }
    160 
    161 GraphicsLayer* RenderLayerScrollableArea::layerForVerticalScrollbar() const
    162 {
    163     return m_box->hasCompositedLayerMapping() ? m_box->compositedLayerMapping()->layerForVerticalScrollbar() : 0;
    164 }
    165 
    166 GraphicsLayer* RenderLayerScrollableArea::layerForScrollCorner() const
    167 {
    168     return m_box->hasCompositedLayerMapping() ? m_box->compositedLayerMapping()->layerForScrollCorner() : 0;
    169 }
    170 
    171 void RenderLayerScrollableArea::invalidateScrollbarRect(Scrollbar* scrollbar, const IntRect& rect)
    172 {
    173     if (scrollbar == m_vBar.get()) {
    174         if (GraphicsLayer* layer = layerForVerticalScrollbar()) {
    175             layer->setNeedsDisplayInRect(rect);
    176             return;
    177         }
    178     } else {
    179         if (GraphicsLayer* layer = layerForHorizontalScrollbar()) {
    180             layer->setNeedsDisplayInRect(rect);
    181             return;
    182         }
    183     }
    184 
    185     IntRect scrollRect = rect;
    186     // If we are not yet inserted into the tree, there is no need to repaint.
    187     if (!m_box->parent())
    188         return;
    189 
    190     if (scrollbar == m_vBar.get())
    191         scrollRect.move(verticalScrollbarStart(0, m_box->width()), m_box->borderTop());
    192     else
    193         scrollRect.move(horizontalScrollbarStart(0), m_box->height() - m_box->borderBottom() - scrollbar->height());
    194     m_box->repaintRectangle(scrollRect);
    195 }
    196 
    197 void RenderLayerScrollableArea::invalidateScrollCornerRect(const IntRect& rect)
    198 {
    199     if (GraphicsLayer* layer = layerForScrollCorner()) {
    200         layer->setNeedsDisplayInRect(rect);
    201         return;
    202     }
    203 
    204     if (m_scrollCorner)
    205         m_scrollCorner->repaintRectangle(rect);
    206     if (m_resizer)
    207         m_resizer->repaintRectangle(rect);
    208 }
    209 
    210 bool RenderLayerScrollableArea::isActive() const
    211 {
    212     Page* page = m_box->frame()->page();
    213     return page && page->focusController().isActive();
    214 }
    215 
    216 bool RenderLayerScrollableArea::isScrollCornerVisible() const
    217 {
    218     return !scrollCornerRect().isEmpty();
    219 }
    220 
    221 static int cornerStart(const RenderStyle* style, int minX, int maxX, int thickness)
    222 {
    223     if (style->shouldPlaceBlockDirectionScrollbarOnLogicalLeft())
    224         return minX + style->borderLeftWidth();
    225     return maxX - thickness - style->borderRightWidth();
    226 }
    227 
    228 static IntRect cornerRect(const RenderStyle* style, const Scrollbar* horizontalScrollbar, const Scrollbar* verticalScrollbar, const IntRect& bounds)
    229 {
    230     int horizontalThickness;
    231     int verticalThickness;
    232     if (!verticalScrollbar && !horizontalScrollbar) {
    233         // FIXME: This isn't right. We need to know the thickness of custom scrollbars
    234         // even when they don't exist in order to set the resizer square size properly.
    235         horizontalThickness = ScrollbarTheme::theme()->scrollbarThickness();
    236         verticalThickness = horizontalThickness;
    237     } else if (verticalScrollbar && !horizontalScrollbar) {
    238         horizontalThickness = verticalScrollbar->width();
    239         verticalThickness = horizontalThickness;
    240     } else if (horizontalScrollbar && !verticalScrollbar) {
    241         verticalThickness = horizontalScrollbar->height();
    242         horizontalThickness = verticalThickness;
    243     } else {
    244         horizontalThickness = verticalScrollbar->width();
    245         verticalThickness = horizontalScrollbar->height();
    246     }
    247     return IntRect(cornerStart(style, bounds.x(), bounds.maxX(), horizontalThickness),
    248         bounds.maxY() - verticalThickness - style->borderBottomWidth(),
    249         horizontalThickness, verticalThickness);
    250 }
    251 
    252 
    253 IntRect RenderLayerScrollableArea::scrollCornerRect() const
    254 {
    255     // We have a scrollbar corner when a scrollbar is visible and not filling the entire length of the box.
    256     // This happens when:
    257     // (a) A resizer is present and at least one scrollbar is present
    258     // (b) Both scrollbars are present.
    259     bool hasHorizontalBar = horizontalScrollbar();
    260     bool hasVerticalBar = verticalScrollbar();
    261     bool hasResizer = m_box->style()->resize() != RESIZE_NONE;
    262     if ((hasHorizontalBar && hasVerticalBar) || (hasResizer && (hasHorizontalBar || hasVerticalBar)))
    263         return cornerRect(m_box->style(), horizontalScrollbar(), verticalScrollbar(), m_box->pixelSnappedBorderBoxRect());
    264     return IntRect();
    265 }
    266 
    267 IntRect RenderLayerScrollableArea::convertFromScrollbarToContainingView(const Scrollbar* scrollbar, const IntRect& scrollbarRect) const
    268 {
    269     RenderView* view = m_box->view();
    270     if (!view)
    271         return scrollbarRect;
    272 
    273     IntRect rect = scrollbarRect;
    274     rect.move(scrollbarOffset(scrollbar));
    275 
    276     return view->frameView()->convertFromRenderer(m_box, rect);
    277 }
    278 
    279 IntRect RenderLayerScrollableArea::convertFromContainingViewToScrollbar(const Scrollbar* scrollbar, const IntRect& parentRect) const
    280 {
    281     RenderView* view = m_box->view();
    282     if (!view)
    283         return parentRect;
    284 
    285     IntRect rect = view->frameView()->convertToRenderer(m_box, parentRect);
    286     rect.move(-scrollbarOffset(scrollbar));
    287     return rect;
    288 }
    289 
    290 IntPoint RenderLayerScrollableArea::convertFromScrollbarToContainingView(const Scrollbar* scrollbar, const IntPoint& scrollbarPoint) const
    291 {
    292     RenderView* view = m_box->view();
    293     if (!view)
    294         return scrollbarPoint;
    295 
    296     IntPoint point = scrollbarPoint;
    297     point.move(scrollbarOffset(scrollbar));
    298     return view->frameView()->convertFromRenderer(m_box, point);
    299 }
    300 
    301 IntPoint RenderLayerScrollableArea::convertFromContainingViewToScrollbar(const Scrollbar* scrollbar, const IntPoint& parentPoint) const
    302 {
    303     RenderView* view = m_box->view();
    304     if (!view)
    305         return parentPoint;
    306 
    307     IntPoint point = view->frameView()->convertToRenderer(m_box, parentPoint);
    308 
    309     point.move(-scrollbarOffset(scrollbar));
    310     return point;
    311 }
    312 
    313 int RenderLayerScrollableArea::scrollSize(ScrollbarOrientation orientation) const
    314 {
    315     IntSize scrollDimensions = maximumScrollPosition() - minimumScrollPosition();
    316     return (orientation == HorizontalScrollbar) ? scrollDimensions.width() : scrollDimensions.height();
    317 }
    318 
    319 void RenderLayerScrollableArea::setScrollOffset(const IntPoint& newScrollOffset)
    320 {
    321     if (!m_box->isMarquee()) {
    322         // Ensure that the dimensions will be computed if they need to be (for overflow:hidden blocks).
    323         if (m_scrollDimensionsDirty)
    324             computeScrollDimensions();
    325     }
    326 
    327     if (scrollOffset() == toIntSize(newScrollOffset))
    328         return;
    329 
    330     setScrollOffset(toIntSize(newScrollOffset));
    331 
    332     Frame* frame = m_box->frame();
    333     InspectorInstrumentation::willScrollLayer(m_box);
    334 
    335     RenderView* view = m_box->view();
    336 
    337     // We should have a RenderView if we're trying to scroll.
    338     ASSERT(view);
    339 
    340     // Update the positions of our child layers (if needed as only fixed layers should be impacted by a scroll).
    341     // We don't update compositing layers, because we need to do a deep update from the compositing ancestor.
    342     bool inLayout = view ? view->frameView()->isInLayout() : false;
    343     if (!inLayout) {
    344         // If we're in the middle of layout, we'll just update layers once layout has finished.
    345         layer()->updateLayerPositionsAfterOverflowScroll();
    346         if (view) {
    347             // Update regions, scrolling may change the clip of a particular region.
    348             view->frameView()->updateAnnotatedRegions();
    349             view->updateWidgetPositions();
    350         }
    351 
    352         updateCompositingLayersAfterScroll();
    353     }
    354 
    355     RenderLayerModelObject* repaintContainer = m_box->containerForRepaint();
    356     if (frame) {
    357         // The caret rect needs to be invalidated after scrolling
    358         frame->selection().setCaretRectNeedsUpdate();
    359 
    360         FloatQuad quadForFakeMouseMoveEvent = FloatQuad(layer()->repainter().repaintRect());
    361         if (repaintContainer)
    362             quadForFakeMouseMoveEvent = repaintContainer->localToAbsoluteQuad(quadForFakeMouseMoveEvent);
    363         frame->eventHandler().dispatchFakeMouseMoveEventSoonInQuad(quadForFakeMouseMoveEvent);
    364     }
    365 
    366     bool requiresRepaint = true;
    367 
    368     if (m_box->view()->compositor()->inCompositingMode()) {
    369         bool onlyScrolledCompositedLayers = scrollsOverflow()
    370             && !layer()->hasVisibleNonLayerContent()
    371             && !layer()->hasNonCompositedChild()
    372             && !layer()->hasBlockSelectionGapBounds()
    373             && !m_box->isMarquee();
    374 
    375         if (usesCompositedScrolling() || onlyScrolledCompositedLayers)
    376             requiresRepaint = false;
    377     }
    378 
    379     // Just schedule a full repaint of our object.
    380     if (view && requiresRepaint)
    381         m_box->repaintUsingContainer(repaintContainer, pixelSnappedIntRect(layer()->repainter().repaintRect()));
    382 
    383     // Schedule the scroll DOM event.
    384     if (m_box->node())
    385         m_box->node()->document().enqueueScrollEventForNode(m_box->node());
    386 
    387     InspectorInstrumentation::didScrollLayer(m_box);
    388 }
    389 
    390 IntPoint RenderLayerScrollableArea::scrollPosition() const
    391 {
    392     return IntPoint(m_scrollOffset);
    393 }
    394 
    395 IntPoint RenderLayerScrollableArea::minimumScrollPosition() const
    396 {
    397     return -scrollOrigin();
    398 }
    399 
    400 IntPoint RenderLayerScrollableArea::maximumScrollPosition() const
    401 {
    402     if (!m_box->hasOverflowClip())
    403         return -scrollOrigin();
    404 
    405     return -scrollOrigin() + enclosingIntRect(m_overflowRect).size() - enclosingIntRect(m_box->clientBoxRect()).size();
    406 }
    407 
    408 IntRect RenderLayerScrollableArea::visibleContentRect(IncludeScrollbarsInRect scrollbarInclusion) const
    409 {
    410     int verticalScrollbarWidth = 0;
    411     int horizontalScrollbarHeight = 0;
    412     if (scrollbarInclusion == IncludeScrollbars) {
    413         verticalScrollbarWidth = (verticalScrollbar() && !verticalScrollbar()->isOverlayScrollbar()) ? verticalScrollbar()->width() : 0;
    414         horizontalScrollbarHeight = (horizontalScrollbar() && !horizontalScrollbar()->isOverlayScrollbar()) ? horizontalScrollbar()->height() : 0;
    415     }
    416 
    417     return IntRect(IntPoint(scrollXOffset(), scrollYOffset()),
    418         IntSize(max(0, layer()->size().width() - verticalScrollbarWidth), max(0, layer()->size().height() - horizontalScrollbarHeight)));
    419 }
    420 
    421 int RenderLayerScrollableArea::visibleHeight() const
    422 {
    423     return layer()->size().height();
    424 }
    425 
    426 int RenderLayerScrollableArea::visibleWidth() const
    427 {
    428     return layer()->size().width();
    429 }
    430 
    431 IntSize RenderLayerScrollableArea::contentsSize() const
    432 {
    433     return IntSize(scrollWidth(), scrollHeight());
    434 }
    435 
    436 IntSize RenderLayerScrollableArea::overhangAmount() const
    437 {
    438     return IntSize();
    439 }
    440 
    441 IntPoint RenderLayerScrollableArea::lastKnownMousePosition() const
    442 {
    443     return m_box->frame() ? m_box->frame()->eventHandler().lastKnownMousePosition() : IntPoint();
    444 }
    445 
    446 bool RenderLayerScrollableArea::shouldSuspendScrollAnimations() const
    447 {
    448     RenderView* view = m_box->view();
    449     if (!view)
    450         return true;
    451     return view->frameView()->shouldSuspendScrollAnimations();
    452 }
    453 
    454 bool RenderLayerScrollableArea::scrollbarsCanBeActive() const
    455 {
    456     RenderView* view = m_box->view();
    457     if (!view)
    458         return false;
    459     return view->frameView()->scrollbarsCanBeActive();
    460 }
    461 
    462 IntRect RenderLayerScrollableArea::scrollableAreaBoundingBox() const
    463 {
    464     return m_box->absoluteBoundingBoxRect();
    465 }
    466 
    467 bool RenderLayerScrollableArea::userInputScrollable(ScrollbarOrientation orientation) const
    468 {
    469     if (m_box->isIntristicallyScrollable(orientation))
    470         return true;
    471 
    472     EOverflow overflowStyle = (orientation == HorizontalScrollbar) ?
    473         m_box->style()->overflowX() : m_box->style()->overflowY();
    474     return (overflowStyle == OSCROLL || overflowStyle == OAUTO || overflowStyle == OOVERLAY);
    475 }
    476 
    477 bool RenderLayerScrollableArea::shouldPlaceVerticalScrollbarOnLeft() const
    478 {
    479     return m_box->style()->shouldPlaceBlockDirectionScrollbarOnLogicalLeft();
    480 }
    481 
    482 int RenderLayerScrollableArea::pageStep(ScrollbarOrientation orientation) const
    483 {
    484     int length = (orientation == HorizontalScrollbar) ?
    485         m_box->pixelSnappedClientWidth() : m_box->pixelSnappedClientHeight();
    486     int minPageStep = static_cast<float>(length) * ScrollableArea::minFractionToStepWhenPaging();
    487     int pageStep = max(minPageStep, length - ScrollableArea::maxOverlapBetweenPages());
    488 
    489     return max(pageStep, 1);
    490 }
    491 
    492 RenderLayer* RenderLayerScrollableArea::layer() const
    493 {
    494     return m_box->layer();
    495 }
    496 
    497 int RenderLayerScrollableArea::scrollWidth() const
    498 {
    499     if (m_scrollDimensionsDirty)
    500         const_cast<RenderLayerScrollableArea*>(this)->computeScrollDimensions();
    501     return snapSizeToPixel(m_overflowRect.width(), m_box->clientLeft() + m_box->x());
    502 }
    503 
    504 int RenderLayerScrollableArea::scrollHeight() const
    505 {
    506     if (m_scrollDimensionsDirty)
    507         const_cast<RenderLayerScrollableArea*>(this)->computeScrollDimensions();
    508     return snapSizeToPixel(m_overflowRect.height(), m_box->clientTop() + m_box->y());
    509 }
    510 
    511 void RenderLayerScrollableArea::computeScrollDimensions()
    512 {
    513     m_scrollDimensionsDirty = false;
    514 
    515     m_overflowRect = m_box->layoutOverflowRect();
    516     m_box->flipForWritingMode(m_overflowRect);
    517 
    518     int scrollableLeftOverflow = m_overflowRect.x() - m_box->borderLeft() - (m_box->style()->shouldPlaceBlockDirectionScrollbarOnLogicalLeft() ? m_box->verticalScrollbarWidth() : 0);
    519     int scrollableTopOverflow = m_overflowRect.y() - m_box->borderTop();
    520     setScrollOrigin(IntPoint(-scrollableLeftOverflow, -scrollableTopOverflow));
    521 }
    522 
    523 void RenderLayerScrollableArea::scrollToOffset(const IntSize& scrollOffset, ScrollOffsetClamping clamp)
    524 {
    525     IntSize newScrollOffset = clamp == ScrollOffsetClamped ? clampScrollOffset(scrollOffset) : scrollOffset;
    526     if (newScrollOffset != adjustedScrollOffset())
    527         scrollToOffsetWithoutAnimation(-scrollOrigin() + newScrollOffset);
    528 }
    529 
    530 void RenderLayerScrollableArea::updateAfterLayout()
    531 {
    532     // List box parts handle the scrollbars by themselves so we have nothing to do.
    533     if (m_box->style()->appearance() == ListboxPart)
    534         return;
    535 
    536     m_scrollDimensionsDirty = true;
    537     IntSize originalScrollOffset = adjustedScrollOffset();
    538 
    539     computeScrollDimensions();
    540 
    541     if (!m_box->isMarquee()) {
    542         // Layout may cause us to be at an invalid scroll position. In this case we need
    543         // to pull our scroll offsets back to the max (or push them up to the min).
    544         IntSize clampedScrollOffset = clampScrollOffset(adjustedScrollOffset());
    545         if (clampedScrollOffset != adjustedScrollOffset())
    546             scrollToOffset(clampedScrollOffset);
    547     }
    548 
    549     if (originalScrollOffset != adjustedScrollOffset())
    550         scrollToOffsetWithoutAnimation(-scrollOrigin() + adjustedScrollOffset());
    551 
    552     bool hasHorizontalOverflow = this->hasHorizontalOverflow();
    553     bool hasVerticalOverflow = this->hasVerticalOverflow();
    554 
    555     // overflow:scroll should just enable/disable.
    556     if (m_box->style()->overflowX() == OSCROLL)
    557         horizontalScrollbar()->setEnabled(hasHorizontalOverflow);
    558     if (m_box->style()->overflowY() == OSCROLL)
    559         verticalScrollbar()->setEnabled(hasVerticalOverflow);
    560 
    561     // overflow:auto may need to lay out again if scrollbars got added/removed.
    562     bool autoHorizontalScrollBarChanged = m_box->hasAutoHorizontalScrollbar() && (hasHorizontalScrollbar() != hasHorizontalOverflow);
    563     bool autoVerticalScrollBarChanged = m_box->hasAutoVerticalScrollbar() && (hasVerticalScrollbar() != hasVerticalOverflow);
    564 
    565     if (autoHorizontalScrollBarChanged || autoVerticalScrollBarChanged) {
    566         if (m_box->hasAutoHorizontalScrollbar())
    567             setHasHorizontalScrollbar(hasHorizontalOverflow);
    568         if (m_box->hasAutoVerticalScrollbar())
    569             setHasVerticalScrollbar(hasVerticalOverflow);
    570 
    571         layer()->updateSelfPaintingLayer();
    572 
    573         // Force an update since we know the scrollbars have changed things.
    574         if (m_box->document().hasAnnotatedRegions())
    575             m_box->document().setAnnotatedRegionsDirty(true);
    576 
    577         m_box->repaint();
    578 
    579         if (m_box->style()->overflowX() == OAUTO || m_box->style()->overflowY() == OAUTO) {
    580             if (!m_inOverflowRelayout) {
    581                 // Our proprietary overflow: overlay value doesn't trigger a layout.
    582                 m_inOverflowRelayout = true;
    583                 SubtreeLayoutScope layoutScope(m_box);
    584                 layoutScope.setNeedsLayout(m_box);
    585                 if (m_box->isRenderBlock()) {
    586                     RenderBlock* block = toRenderBlock(m_box);
    587                     block->scrollbarsChanged(autoHorizontalScrollBarChanged, autoVerticalScrollBarChanged);
    588                     block->layoutBlock(true);
    589                 } else {
    590                     m_box->layout();
    591                 }
    592                 m_inOverflowRelayout = false;
    593             }
    594         }
    595     }
    596 
    597     // Set up the range (and page step/line step).
    598     if (Scrollbar* horizontalScrollbar = this->horizontalScrollbar()) {
    599         int clientWidth = m_box->pixelSnappedClientWidth();
    600         horizontalScrollbar->setProportion(clientWidth, overflowRect().width());
    601     }
    602     if (Scrollbar* verticalScrollbar = this->verticalScrollbar()) {
    603         int clientHeight = m_box->pixelSnappedClientHeight();
    604         verticalScrollbar->setProportion(clientHeight, overflowRect().height());
    605     }
    606 
    607     updateScrollableAreaSet(hasScrollableHorizontalOverflow() || hasScrollableVerticalOverflow());
    608 
    609     // Composited scrolling may need to be enabled or disabled if the amount of overflow changed.
    610     if (m_box->view() && m_box->view()->compositor()->updateLayerCompositingState(m_box->layer()))
    611         m_box->view()->compositor()->setCompositingLayersNeedRebuild();
    612 }
    613 
    614 bool RenderLayerScrollableArea::hasHorizontalOverflow() const
    615 {
    616     ASSERT(!m_scrollDimensionsDirty);
    617 
    618     return scrollWidth() > m_box->pixelSnappedClientWidth();
    619 }
    620 
    621 bool RenderLayerScrollableArea::hasVerticalOverflow() const
    622 {
    623     ASSERT(!m_scrollDimensionsDirty);
    624 
    625     return scrollHeight() > m_box->pixelSnappedClientHeight();
    626 }
    627 
    628 bool RenderLayerScrollableArea::hasScrollableHorizontalOverflow() const
    629 {
    630     return hasHorizontalOverflow() && m_box->scrollsOverflowX();
    631 }
    632 
    633 bool RenderLayerScrollableArea::hasScrollableVerticalOverflow() const
    634 {
    635     return hasVerticalOverflow() && m_box->scrollsOverflowY();
    636 }
    637 
    638 static bool overflowRequiresScrollbar(EOverflow overflow)
    639 {
    640     return overflow == OSCROLL;
    641 }
    642 
    643 static bool overflowDefinesAutomaticScrollbar(EOverflow overflow)
    644 {
    645     return overflow == OAUTO || overflow == OOVERLAY;
    646 }
    647 
    648 void RenderLayerScrollableArea::updateAfterStyleChange(const RenderStyle* oldStyle)
    649 {
    650     // List box parts handle the scrollbars by themselves so we have nothing to do.
    651     if (m_box->style()->appearance() == ListboxPart)
    652         return;
    653 
    654     if (!m_scrollDimensionsDirty)
    655         updateScrollableAreaSet(hasScrollableHorizontalOverflow() || hasScrollableVerticalOverflow());
    656 
    657     EOverflow overflowX = m_box->style()->overflowX();
    658     EOverflow overflowY = m_box->style()->overflowY();
    659 
    660     // To avoid doing a relayout in updateScrollbarsAfterLayout, we try to keep any automatic scrollbar that was already present.
    661     bool needsHorizontalScrollbar = (hasHorizontalScrollbar() && overflowDefinesAutomaticScrollbar(overflowX)) || overflowRequiresScrollbar(overflowX);
    662     bool needsVerticalScrollbar = (hasVerticalScrollbar() && overflowDefinesAutomaticScrollbar(overflowY)) || overflowRequiresScrollbar(overflowY);
    663     setHasHorizontalScrollbar(needsHorizontalScrollbar);
    664     setHasVerticalScrollbar(needsVerticalScrollbar);
    665 
    666     // With overflow: scroll, scrollbars are always visible but may be disabled.
    667     // When switching to another value, we need to re-enable them (see bug 11985).
    668     if (needsHorizontalScrollbar && oldStyle && oldStyle->overflowX() == OSCROLL && overflowX != OSCROLL) {
    669         ASSERT(hasHorizontalScrollbar());
    670         m_hBar->setEnabled(true);
    671     }
    672 
    673     if (needsVerticalScrollbar && oldStyle && oldStyle->overflowY() == OSCROLL && overflowY != OSCROLL) {
    674         ASSERT(hasVerticalScrollbar());
    675         m_vBar->setEnabled(true);
    676     }
    677 
    678     // FIXME: Need to detect a swap from custom to native scrollbars (and vice versa).
    679     if (m_hBar)
    680         m_hBar->styleChanged();
    681     if (m_vBar)
    682         m_vBar->styleChanged();
    683 
    684     updateScrollCornerStyle();
    685     updateResizerAreaSet();
    686     updateResizerStyle();
    687 }
    688 
    689 IntSize RenderLayerScrollableArea::clampScrollOffset(const IntSize& scrollOffset) const
    690 {
    691     int maxX = scrollWidth() - m_box->pixelSnappedClientWidth();
    692     int maxY = scrollHeight() - m_box->pixelSnappedClientHeight();
    693 
    694     int x = std::max(std::min(scrollOffset.width(), maxX), 0);
    695     int y = std::max(std::min(scrollOffset.height(), maxY), 0);
    696     return IntSize(x, y);
    697 }
    698 
    699 IntRect RenderLayerScrollableArea::rectForHorizontalScrollbar(const IntRect& borderBoxRect) const
    700 {
    701     if (!m_hBar)
    702         return IntRect();
    703 
    704     const IntRect& scrollCorner = scrollCornerRect();
    705 
    706     return IntRect(horizontalScrollbarStart(borderBoxRect.x()),
    707         borderBoxRect.maxY() - m_box->borderBottom() - m_hBar->height(),
    708         borderBoxRect.width() - (m_box->borderLeft() + m_box->borderRight()) - scrollCorner.width(),
    709         m_hBar->height());
    710 }
    711 
    712 IntRect RenderLayerScrollableArea::rectForVerticalScrollbar(const IntRect& borderBoxRect) const
    713 {
    714     if (!m_vBar)
    715         return IntRect();
    716 
    717     const IntRect& scrollCorner = scrollCornerRect();
    718 
    719     return IntRect(verticalScrollbarStart(borderBoxRect.x(), borderBoxRect.maxX()),
    720         borderBoxRect.y() + m_box->borderTop(),
    721         m_vBar->width(),
    722         borderBoxRect.height() - (m_box->borderTop() + m_box->borderBottom()) - scrollCorner.height());
    723 }
    724 
    725 LayoutUnit RenderLayerScrollableArea::verticalScrollbarStart(int minX, int maxX) const
    726 {
    727     if (m_box->style()->shouldPlaceBlockDirectionScrollbarOnLogicalLeft())
    728         return minX + m_box->borderLeft();
    729     return maxX - m_box->borderRight() - m_vBar->width();
    730 }
    731 
    732 LayoutUnit RenderLayerScrollableArea::horizontalScrollbarStart(int minX) const
    733 {
    734     int x = minX + m_box->borderLeft();
    735     if (m_box->style()->shouldPlaceBlockDirectionScrollbarOnLogicalLeft())
    736         x += m_vBar ? m_vBar->width() : resizerCornerRect(m_box->pixelSnappedBorderBoxRect(), ResizerForPointer).width();
    737     return x;
    738 }
    739 
    740 IntSize RenderLayerScrollableArea::scrollbarOffset(const Scrollbar* scrollbar) const
    741 {
    742     if (scrollbar == m_vBar.get())
    743         return IntSize(verticalScrollbarStart(0, m_box->width()), m_box->borderTop());
    744 
    745     if (scrollbar == m_hBar.get())
    746         return IntSize(horizontalScrollbarStart(0), m_box->height() - m_box->borderBottom() - scrollbar->height());
    747 
    748     ASSERT_NOT_REACHED();
    749     return IntSize();
    750 }
    751 
    752 static inline RenderObject* rendererForScrollbar(RenderObject* renderer)
    753 {
    754     if (Node* node = renderer->node()) {
    755         if (ShadowRoot* shadowRoot = node->containingShadowRoot()) {
    756             if (shadowRoot->type() == ShadowRoot::UserAgentShadowRoot)
    757                 return shadowRoot->host()->renderer();
    758         }
    759     }
    760 
    761     return renderer;
    762 }
    763 
    764 PassRefPtr<Scrollbar> RenderLayerScrollableArea::createScrollbar(ScrollbarOrientation orientation)
    765 {
    766     RefPtr<Scrollbar> widget;
    767     RenderObject* actualRenderer = rendererForScrollbar(m_box);
    768     bool hasCustomScrollbarStyle = actualRenderer->isBox() && actualRenderer->style()->hasPseudoStyle(SCROLLBAR);
    769     if (hasCustomScrollbarStyle) {
    770         widget = RenderScrollbar::createCustomScrollbar(this, orientation, actualRenderer->node());
    771     } else {
    772         widget = Scrollbar::create(this, orientation, RegularScrollbar);
    773         if (orientation == HorizontalScrollbar)
    774             didAddScrollbar(widget.get(), HorizontalScrollbar);
    775         else
    776             didAddScrollbar(widget.get(), VerticalScrollbar);
    777     }
    778     m_box->document().view()->addChild(widget.get());
    779     return widget.release();
    780 }
    781 
    782 void RenderLayerScrollableArea::destroyScrollbar(ScrollbarOrientation orientation)
    783 {
    784     RefPtr<Scrollbar>& scrollbar = orientation == HorizontalScrollbar ? m_hBar : m_vBar;
    785     if (!scrollbar)
    786         return;
    787 
    788     if (!scrollbar->isCustomScrollbar())
    789         willRemoveScrollbar(scrollbar.get(), orientation);
    790 
    791     scrollbar->removeFromParent();
    792     scrollbar->disconnectFromScrollableArea();
    793     scrollbar = 0;
    794 }
    795 
    796 void RenderLayerScrollableArea::setHasHorizontalScrollbar(bool hasScrollbar)
    797 {
    798     if (hasScrollbar == hasHorizontalScrollbar())
    799         return;
    800 
    801     if (hasScrollbar)
    802         m_hBar = createScrollbar(HorizontalScrollbar);
    803     else
    804         destroyScrollbar(HorizontalScrollbar);
    805 
    806     // Destroying or creating one bar can cause our scrollbar corner to come and go. We need to update the opposite scrollbar's style.
    807     if (m_hBar)
    808         m_hBar->styleChanged();
    809     if (m_vBar)
    810         m_vBar->styleChanged();
    811 
    812     // Force an update since we know the scrollbars have changed things.
    813     if (m_box->document().hasAnnotatedRegions())
    814         m_box->document().setAnnotatedRegionsDirty(true);
    815 }
    816 
    817 void RenderLayerScrollableArea::setHasVerticalScrollbar(bool hasScrollbar)
    818 {
    819     if (hasScrollbar == hasVerticalScrollbar())
    820         return;
    821 
    822     if (hasScrollbar)
    823         m_vBar = createScrollbar(VerticalScrollbar);
    824     else
    825         destroyScrollbar(VerticalScrollbar);
    826 
    827     // Destroying or creating one bar can cause our scrollbar corner to come and go. We need to update the opposite scrollbar's style.
    828     if (m_hBar)
    829         m_hBar->styleChanged();
    830     if (m_vBar)
    831         m_vBar->styleChanged();
    832 
    833     // Force an update since we know the scrollbars have changed things.
    834     if (m_box->document().hasAnnotatedRegions())
    835         m_box->document().setAnnotatedRegionsDirty(true);
    836 }
    837 
    838 int RenderLayerScrollableArea::verticalScrollbarWidth(OverlayScrollbarSizeRelevancy relevancy) const
    839 {
    840     if (!m_vBar || (m_vBar->isOverlayScrollbar() && (relevancy == IgnoreOverlayScrollbarSize || !m_vBar->shouldParticipateInHitTesting())))
    841         return 0;
    842     return m_vBar->width();
    843 }
    844 
    845 int RenderLayerScrollableArea::horizontalScrollbarHeight(OverlayScrollbarSizeRelevancy relevancy) const
    846 {
    847     if (!m_hBar || (m_hBar->isOverlayScrollbar() && (relevancy == IgnoreOverlayScrollbarSize || !m_hBar->shouldParticipateInHitTesting())))
    848         return 0;
    849     return m_hBar->height();
    850 }
    851 
    852 void RenderLayerScrollableArea::positionOverflowControls()
    853 {
    854     RenderGeometryMap geometryMap(UseTransforms);
    855     RenderView* view = m_box->view();
    856     if (m_box->layer() != view->layer() && m_box->layer()->parent())
    857         geometryMap.pushMappingsToAncestor(m_box->layer()->parent(), 0);
    858 
    859     LayoutPoint offsetFromRoot = LayoutPoint(geometryMap.absolutePoint(FloatPoint()));
    860     positionOverflowControls(toIntSize(roundedIntPoint(offsetFromRoot)));
    861 }
    862 
    863 void RenderLayerScrollableArea::positionOverflowControls(const IntSize& offsetFromRoot)
    864 {
    865     if (!hasScrollbar() && !m_box->canResize())
    866         return;
    867 
    868     const IntRect borderBox = m_box->pixelSnappedBorderBoxRect();
    869     if (Scrollbar* verticalScrollbar = this->verticalScrollbar()) {
    870         IntRect vBarRect = rectForVerticalScrollbar(borderBox);
    871         vBarRect.move(offsetFromRoot);
    872         verticalScrollbar->setFrameRect(vBarRect);
    873     }
    874 
    875     if (Scrollbar* horizontalScrollbar = this->horizontalScrollbar()) {
    876         IntRect hBarRect = rectForHorizontalScrollbar(borderBox);
    877         hBarRect.move(offsetFromRoot);
    878         horizontalScrollbar->setFrameRect(hBarRect);
    879     }
    880 
    881     const IntRect& scrollCorner = scrollCornerRect();
    882     if (m_scrollCorner)
    883         m_scrollCorner->setFrameRect(scrollCorner);
    884 
    885     if (m_resizer)
    886         m_resizer->setFrameRect(resizerCornerRect(borderBox, ResizerForPointer));
    887 
    888     // FIXME, this should eventually be removed, once we are certain that composited
    889     // controls get correctly positioned on a compositor update. For now, conservatively
    890     // leaving this unchanged.
    891     if (m_box->hasCompositedLayerMapping())
    892         m_box->compositedLayerMapping()->positionOverflowControlsLayers(offsetFromRoot);
    893 }
    894 
    895 bool RenderLayerScrollableArea::scrollsOverflow() const
    896 {
    897     if (FrameView* frameView = m_box->view()->frameView())
    898         return frameView->containsScrollableArea(this);
    899 
    900     return false;
    901 }
    902 
    903 void RenderLayerScrollableArea::updateScrollCornerStyle()
    904 {
    905     RenderObject* actualRenderer = rendererForScrollbar(m_box);
    906     RefPtr<RenderStyle> corner = m_box->hasOverflowClip() ? actualRenderer->getUncachedPseudoStyle(PseudoStyleRequest(SCROLLBAR_CORNER), actualRenderer->style()) : PassRefPtr<RenderStyle>(0);
    907     if (corner) {
    908         if (!m_scrollCorner) {
    909             m_scrollCorner = RenderScrollbarPart::createAnonymous(&m_box->document());
    910             m_scrollCorner->setParent(m_box);
    911         }
    912         m_scrollCorner->setStyle(corner.release());
    913     } else if (m_scrollCorner) {
    914         m_scrollCorner->destroy();
    915         m_scrollCorner = 0;
    916     }
    917 }
    918 
    919 void RenderLayerScrollableArea::paintOverflowControls(GraphicsContext* context, const IntPoint& paintOffset, const IntRect& damageRect, bool paintingOverlayControls)
    920 {
    921     // Don't do anything if we have no overflow.
    922     if (!m_box->hasOverflowClip())
    923         return;
    924 
    925     IntPoint adjustedPaintOffset = paintOffset;
    926     if (paintingOverlayControls)
    927         adjustedPaintOffset = m_cachedOverlayScrollbarOffset;
    928 
    929     // Move the scrollbar widgets if necessary. We normally move and resize widgets during layout,
    930     // but sometimes widgets can move without layout occurring (most notably when you scroll a
    931     // document that contains fixed positioned elements).
    932     positionOverflowControls(toIntSize(adjustedPaintOffset));
    933 
    934     // Overlay scrollbars paint in a second pass through the layer tree so that they will paint
    935     // on top of everything else. If this is the normal painting pass, paintingOverlayControls
    936     // will be false, and we should just tell the root layer that there are overlay scrollbars
    937     // that need to be painted. That will cause the second pass through the layer tree to run,
    938     // and we'll paint the scrollbars then. In the meantime, cache tx and ty so that the
    939     // second pass doesn't need to re-enter the RenderTree to get it right.
    940     if (hasOverlayScrollbars() && !paintingOverlayControls) {
    941         m_cachedOverlayScrollbarOffset = paintOffset;
    942         // It's not necessary to do the second pass if the scrollbars paint into layers.
    943         if ((m_hBar && layerForHorizontalScrollbar()) || (m_vBar && layerForVerticalScrollbar()))
    944             return;
    945         IntRect localDamgeRect = damageRect;
    946         localDamgeRect.moveBy(-paintOffset);
    947         if (!overflowControlsIntersectRect(localDamgeRect))
    948             return;
    949 
    950         RenderView* renderView = m_box->view();
    951 
    952         RenderLayer* paintingRoot = layer()->enclosingCompositingLayer();
    953         if (!paintingRoot)
    954             paintingRoot = renderView->layer();
    955 
    956         paintingRoot->setContainsDirtyOverlayScrollbars(true);
    957         return;
    958     }
    959 
    960     // This check is required to avoid painting custom CSS scrollbars twice.
    961     if (paintingOverlayControls && !hasOverlayScrollbars())
    962         return;
    963 
    964     // Now that we're sure the scrollbars are in the right place, paint them.
    965     if (m_hBar && !layerForHorizontalScrollbar())
    966         m_hBar->paint(context, damageRect);
    967     if (m_vBar && !layerForVerticalScrollbar())
    968         m_vBar->paint(context, damageRect);
    969 
    970     if (layerForScrollCorner())
    971         return;
    972 
    973     // We fill our scroll corner with white if we have a scrollbar that doesn't run all the way up to the
    974     // edge of the box.
    975     paintScrollCorner(context, adjustedPaintOffset, damageRect);
    976 
    977     // Paint our resizer last, since it sits on top of the scroll corner.
    978     paintResizer(context, adjustedPaintOffset, damageRect);
    979 }
    980 
    981 void RenderLayerScrollableArea::paintScrollCorner(GraphicsContext* context, const IntPoint& paintOffset, const IntRect& damageRect)
    982 {
    983     IntRect absRect = scrollCornerRect();
    984     absRect.moveBy(paintOffset);
    985     if (!absRect.intersects(damageRect))
    986         return;
    987 
    988     if (context->updatingControlTints()) {
    989         updateScrollCornerStyle();
    990         return;
    991     }
    992 
    993     if (m_scrollCorner) {
    994         m_scrollCorner->paintIntoRect(context, paintOffset, absRect);
    995         return;
    996     }
    997 
    998     // We don't want to paint white if we have overlay scrollbars, since we need
    999     // to see what is behind it.
   1000     if (!hasOverlayScrollbars())
   1001         context->fillRect(absRect, Color::white);
   1002 }
   1003 
   1004 bool RenderLayerScrollableArea::hitTestOverflowControls(HitTestResult& result, const IntPoint& localPoint)
   1005 {
   1006     if (!hasScrollbar() && !m_box->canResize())
   1007         return false;
   1008 
   1009     IntRect resizeControlRect;
   1010     if (m_box->style()->resize() != RESIZE_NONE) {
   1011         resizeControlRect = resizerCornerRect(m_box->pixelSnappedBorderBoxRect(), ResizerForPointer);
   1012         if (resizeControlRect.contains(localPoint))
   1013             return true;
   1014     }
   1015 
   1016     int resizeControlSize = max(resizeControlRect.height(), 0);
   1017     if (m_vBar && m_vBar->shouldParticipateInHitTesting()) {
   1018         LayoutRect vBarRect(verticalScrollbarStart(0, m_box->width()),
   1019             m_box->borderTop(),
   1020             m_vBar->width(),
   1021             m_box->height() - (m_box->borderTop() + m_box->borderBottom()) - (m_hBar ? m_hBar->height() : resizeControlSize));
   1022         if (vBarRect.contains(localPoint)) {
   1023             result.setScrollbar(m_vBar.get());
   1024             return true;
   1025         }
   1026     }
   1027 
   1028     resizeControlSize = max(resizeControlRect.width(), 0);
   1029     if (m_hBar && m_hBar->shouldParticipateInHitTesting()) {
   1030         LayoutRect hBarRect(horizontalScrollbarStart(0),
   1031             m_box->height() - m_box->borderBottom() - m_hBar->height(),
   1032             m_box->width() - (m_box->borderLeft() + m_box->borderRight()) - (m_vBar ? m_vBar->width() : resizeControlSize),
   1033             m_hBar->height());
   1034         if (hBarRect.contains(localPoint)) {
   1035             result.setScrollbar(m_hBar.get());
   1036             return true;
   1037         }
   1038     }
   1039 
   1040     // FIXME: We should hit test the m_scrollCorner and pass it back through the result.
   1041 
   1042     return false;
   1043 }
   1044 
   1045 IntRect RenderLayerScrollableArea::resizerCornerRect(const IntRect& bounds, ResizerHitTestType resizerHitTestType) const
   1046 {
   1047     if (m_box->style()->resize() == RESIZE_NONE)
   1048         return IntRect();
   1049     IntRect corner = cornerRect(m_box->style(), horizontalScrollbar(), verticalScrollbar(), bounds);
   1050 
   1051     if (resizerHitTestType == ResizerForTouch) {
   1052         // We make the resizer virtually larger for touch hit testing. With the
   1053         // expanding ratio k = ResizerControlExpandRatioForTouch, we first move
   1054         // the resizer rect (of width w & height h), by (-w * (k-1), -h * (k-1)),
   1055         // then expand the rect by new_w/h = w/h * k.
   1056         int expandRatio = ResizerControlExpandRatioForTouch - 1;
   1057         corner.move(-corner.width() * expandRatio, -corner.height() * expandRatio);
   1058         corner.expand(corner.width() * expandRatio, corner.height() * expandRatio);
   1059     }
   1060 
   1061     return corner;
   1062 }
   1063 
   1064 IntRect RenderLayerScrollableArea::scrollCornerAndResizerRect() const
   1065 {
   1066     IntRect scrollCornerAndResizer = scrollCornerRect();
   1067     if (scrollCornerAndResizer.isEmpty())
   1068         scrollCornerAndResizer = resizerCornerRect(m_box->pixelSnappedBorderBoxRect(), ResizerForPointer);
   1069     return scrollCornerAndResizer;
   1070 }
   1071 
   1072 bool RenderLayerScrollableArea::overflowControlsIntersectRect(const IntRect& localRect) const
   1073 {
   1074     const IntRect borderBox = m_box->pixelSnappedBorderBoxRect();
   1075 
   1076     if (rectForHorizontalScrollbar(borderBox).intersects(localRect))
   1077         return true;
   1078 
   1079     if (rectForVerticalScrollbar(borderBox).intersects(localRect))
   1080         return true;
   1081 
   1082     if (scrollCornerRect().intersects(localRect))
   1083         return true;
   1084 
   1085     if (resizerCornerRect(borderBox, ResizerForPointer).intersects(localRect))
   1086         return true;
   1087 
   1088     return false;
   1089 }
   1090 
   1091 void RenderLayerScrollableArea::paintResizer(GraphicsContext* context, const IntPoint& paintOffset, const IntRect& damageRect)
   1092 {
   1093     if (m_box->style()->resize() == RESIZE_NONE)
   1094         return;
   1095 
   1096     IntRect absRect = resizerCornerRect(m_box->pixelSnappedBorderBoxRect(), ResizerForPointer);
   1097     absRect.moveBy(paintOffset);
   1098     if (!absRect.intersects(damageRect))
   1099         return;
   1100 
   1101     if (context->updatingControlTints()) {
   1102         updateResizerStyle();
   1103         return;
   1104     }
   1105 
   1106     if (m_resizer) {
   1107         m_resizer->paintIntoRect(context, paintOffset, absRect);
   1108         return;
   1109     }
   1110 
   1111     drawPlatformResizerImage(context, absRect);
   1112 
   1113     // Draw a frame around the resizer (1px grey line) if there are any scrollbars present.
   1114     // Clipping will exclude the right and bottom edges of this frame.
   1115     if (!hasOverlayScrollbars() && hasScrollbar()) {
   1116         GraphicsContextStateSaver stateSaver(*context);
   1117         context->clip(absRect);
   1118         IntRect largerCorner = absRect;
   1119         largerCorner.setSize(IntSize(largerCorner.width() + 1, largerCorner.height() + 1));
   1120         context->setStrokeColor(Color(217, 217, 217));
   1121         context->setStrokeThickness(1.0f);
   1122         context->setFillColor(Color::transparent);
   1123         context->drawRect(largerCorner);
   1124     }
   1125 }
   1126 
   1127 bool RenderLayerScrollableArea::isPointInResizeControl(const IntPoint& absolutePoint, ResizerHitTestType resizerHitTestType) const
   1128 {
   1129     if (!m_box->canResize())
   1130         return false;
   1131 
   1132     IntPoint localPoint = roundedIntPoint(m_box->absoluteToLocal(absolutePoint, UseTransforms));
   1133     IntRect localBounds(0, 0, m_box->pixelSnappedWidth(), m_box->pixelSnappedHeight());
   1134     return resizerCornerRect(localBounds, resizerHitTestType).contains(localPoint);
   1135 }
   1136 
   1137 bool RenderLayerScrollableArea::hitTestResizerInFragments(const LayerFragments& layerFragments, const HitTestLocation& hitTestLocation) const
   1138 {
   1139     if (!m_box->canResize())
   1140         return false;
   1141 
   1142     if (layerFragments.isEmpty())
   1143         return false;
   1144 
   1145     for (int i = layerFragments.size() - 1; i >= 0; --i) {
   1146         const LayerFragment& fragment = layerFragments.at(i);
   1147         if (fragment.backgroundRect.intersects(hitTestLocation) && resizerCornerRect(pixelSnappedIntRect(fragment.layerBounds), ResizerForPointer).contains(hitTestLocation.roundedPoint()))
   1148             return true;
   1149     }
   1150 
   1151     return false;
   1152 }
   1153 
   1154 void RenderLayerScrollableArea::updateResizerAreaSet()
   1155 {
   1156     Frame* frame = m_box->frame();
   1157     if (!frame)
   1158         return;
   1159     FrameView* frameView = frame->view();
   1160     if (!frameView)
   1161         return;
   1162     if (m_box->canResize())
   1163         frameView->addResizerArea(m_box);
   1164     else
   1165         frameView->removeResizerArea(m_box);
   1166 }
   1167 
   1168 void RenderLayerScrollableArea::updateResizerStyle()
   1169 {
   1170     RenderObject* actualRenderer = rendererForScrollbar(m_box);
   1171     RefPtr<RenderStyle> resizer = m_box->hasOverflowClip() ? actualRenderer->getUncachedPseudoStyle(PseudoStyleRequest(RESIZER), actualRenderer->style()) : PassRefPtr<RenderStyle>(0);
   1172     if (resizer) {
   1173         if (!m_resizer) {
   1174             m_resizer = RenderScrollbarPart::createAnonymous(&m_box->document());
   1175             m_resizer->setParent(m_box);
   1176         }
   1177         m_resizer->setStyle(resizer.release());
   1178     } else if (m_resizer) {
   1179         m_resizer->destroy();
   1180         m_resizer = 0;
   1181     }
   1182 }
   1183 
   1184 void RenderLayerScrollableArea::drawPlatformResizerImage(GraphicsContext* context, IntRect resizerCornerRect)
   1185 {
   1186     float deviceScaleFactor = WebCore::deviceScaleFactor(m_box->frame());
   1187 
   1188     RefPtr<Image> resizeCornerImage;
   1189     IntSize cornerResizerSize;
   1190     if (deviceScaleFactor >= 2) {
   1191         DEFINE_STATIC_REF(Image, resizeCornerImageHiRes, (Image::loadPlatformResource("textAreaResizeCorner@2x")));
   1192         resizeCornerImage = resizeCornerImageHiRes;
   1193         cornerResizerSize = resizeCornerImage->size();
   1194         cornerResizerSize.scale(0.5f);
   1195     } else {
   1196         DEFINE_STATIC_REF(Image, resizeCornerImageLoRes, (Image::loadPlatformResource("textAreaResizeCorner")));
   1197         resizeCornerImage = resizeCornerImageLoRes;
   1198         cornerResizerSize = resizeCornerImage->size();
   1199     }
   1200 
   1201     if (m_box->style()->shouldPlaceBlockDirectionScrollbarOnLogicalLeft()) {
   1202         context->save();
   1203         context->translate(resizerCornerRect.x() + cornerResizerSize.width(), resizerCornerRect.y() + resizerCornerRect.height() - cornerResizerSize.height());
   1204         context->scale(FloatSize(-1.0, 1.0));
   1205         context->drawImage(resizeCornerImage.get(), IntRect(IntPoint(), cornerResizerSize));
   1206         context->restore();
   1207         return;
   1208     }
   1209     IntRect imageRect(resizerCornerRect.maxXMaxYCorner() - cornerResizerSize, cornerResizerSize);
   1210     context->drawImage(resizeCornerImage.get(), imageRect);
   1211 }
   1212 
   1213 IntSize RenderLayerScrollableArea::offsetFromResizeCorner(const IntPoint& absolutePoint) const
   1214 {
   1215     // Currently the resize corner is either the bottom right corner or the bottom left corner.
   1216     // FIXME: This assumes the location is 0, 0. Is this guaranteed to always be the case?
   1217     IntSize elementSize = layer()->size();
   1218     if (m_box->style()->shouldPlaceBlockDirectionScrollbarOnLogicalLeft())
   1219         elementSize.setWidth(0);
   1220     IntPoint resizerPoint = IntPoint(elementSize);
   1221     IntPoint localPoint = roundedIntPoint(m_box->absoluteToLocal(absolutePoint, UseTransforms));
   1222     return localPoint - resizerPoint;
   1223 }
   1224 
   1225 void RenderLayerScrollableArea::resize(const PlatformEvent& evt, const LayoutSize& oldOffset)
   1226 {
   1227     // FIXME: This should be possible on generated content but is not right now.
   1228     if (!inResizeMode() || !m_box->canResize() || !m_box->node())
   1229         return;
   1230 
   1231     ASSERT(m_box->node()->isElementNode());
   1232     Element* element = toElement(m_box->node());
   1233 
   1234     Document& document = element->document();
   1235 
   1236     IntPoint pos;
   1237     const PlatformGestureEvent* gevt = 0;
   1238 
   1239     switch (evt.type()) {
   1240     case PlatformEvent::MouseMoved:
   1241         if (!document.frame()->eventHandler().mousePressed())
   1242             return;
   1243         pos = static_cast<const PlatformMouseEvent*>(&evt)->position();
   1244         break;
   1245     case PlatformEvent::GestureScrollUpdate:
   1246     case PlatformEvent::GestureScrollUpdateWithoutPropagation:
   1247         pos = static_cast<const PlatformGestureEvent*>(&evt)->position();
   1248         gevt = static_cast<const PlatformGestureEvent*>(&evt);
   1249         pos = gevt->position();
   1250         pos.move(gevt->deltaX(), gevt->deltaY());
   1251         break;
   1252     default:
   1253         ASSERT_NOT_REACHED();
   1254     }
   1255 
   1256     float zoomFactor = m_box->style()->effectiveZoom();
   1257 
   1258     LayoutSize newOffset = offsetFromResizeCorner(document.view()->windowToContents(pos));
   1259     newOffset.setWidth(newOffset.width() / zoomFactor);
   1260     newOffset.setHeight(newOffset.height() / zoomFactor);
   1261 
   1262     LayoutSize currentSize = LayoutSize(m_box->width() / zoomFactor, m_box->height() / zoomFactor);
   1263     LayoutSize minimumSize = element->minimumSizeForResizing().shrunkTo(currentSize);
   1264     element->setMinimumSizeForResizing(minimumSize);
   1265 
   1266     LayoutSize adjustedOldOffset = LayoutSize(oldOffset.width() / zoomFactor, oldOffset.height() / zoomFactor);
   1267     if (m_box->style()->shouldPlaceBlockDirectionScrollbarOnLogicalLeft()) {
   1268         newOffset.setWidth(-newOffset.width());
   1269         adjustedOldOffset.setWidth(-adjustedOldOffset.width());
   1270     }
   1271 
   1272     LayoutSize difference = (currentSize + newOffset - adjustedOldOffset).expandedTo(minimumSize) - currentSize;
   1273 
   1274     bool isBoxSizingBorder = m_box->style()->boxSizing() == BORDER_BOX;
   1275 
   1276     EResize resize = m_box->style()->resize();
   1277     if (resize != RESIZE_VERTICAL && difference.width()) {
   1278         if (element->isFormControlElement()) {
   1279             // Make implicit margins from the theme explicit (see <http://bugs.webkit.org/show_bug.cgi?id=9547>).
   1280             element->setInlineStyleProperty(CSSPropertyMarginLeft, m_box->marginLeft() / zoomFactor, CSSPrimitiveValue::CSS_PX);
   1281             element->setInlineStyleProperty(CSSPropertyMarginRight, m_box->marginRight() / zoomFactor, CSSPrimitiveValue::CSS_PX);
   1282         }
   1283         LayoutUnit baseWidth = m_box->width() - (isBoxSizingBorder ? LayoutUnit() : m_box->borderAndPaddingWidth());
   1284         baseWidth = baseWidth / zoomFactor;
   1285         element->setInlineStyleProperty(CSSPropertyWidth, roundToInt(baseWidth + difference.width()), CSSPrimitiveValue::CSS_PX);
   1286     }
   1287 
   1288     if (resize != RESIZE_HORIZONTAL && difference.height()) {
   1289         if (element->isFormControlElement()) {
   1290             // Make implicit margins from the theme explicit (see <http://bugs.webkit.org/show_bug.cgi?id=9547>).
   1291             element->setInlineStyleProperty(CSSPropertyMarginTop, m_box->marginTop() / zoomFactor, CSSPrimitiveValue::CSS_PX);
   1292             element->setInlineStyleProperty(CSSPropertyMarginBottom, m_box->marginBottom() / zoomFactor, CSSPrimitiveValue::CSS_PX);
   1293         }
   1294         LayoutUnit baseHeight = m_box->height() - (isBoxSizingBorder ? LayoutUnit() : m_box->borderAndPaddingHeight());
   1295         baseHeight = baseHeight / zoomFactor;
   1296         element->setInlineStyleProperty(CSSPropertyHeight, roundToInt(baseHeight + difference.height()), CSSPrimitiveValue::CSS_PX);
   1297     }
   1298 
   1299     document.updateLayout();
   1300 
   1301     // FIXME (Radar 4118564): We should also autoscroll the window as necessary to keep the point under the cursor in view.
   1302 }
   1303 
   1304 LayoutRect RenderLayerScrollableArea::exposeRect(const LayoutRect& rect, const ScrollAlignment& alignX, const ScrollAlignment& alignY)
   1305 {
   1306     LayoutRect localExposeRect(m_box->absoluteToLocalQuad(FloatQuad(FloatRect(rect)), UseTransforms).boundingBox());
   1307     LayoutRect layerBounds(0, 0, m_box->clientWidth(), m_box->clientHeight());
   1308     LayoutRect r = ScrollAlignment::getRectToExpose(layerBounds, localExposeRect, alignX, alignY);
   1309 
   1310     IntSize clampedScrollOffset = clampScrollOffset(adjustedScrollOffset() + toIntSize(roundedIntRect(r).location()));
   1311     if (clampedScrollOffset == adjustedScrollOffset())
   1312         return rect;
   1313 
   1314     IntSize oldScrollOffset = adjustedScrollOffset();
   1315     scrollToOffset(clampedScrollOffset);
   1316     IntSize scrollOffsetDifference = adjustedScrollOffset() - oldScrollOffset;
   1317     localExposeRect.move(-scrollOffsetDifference);
   1318     return LayoutRect(m_box->localToAbsoluteQuad(FloatQuad(FloatRect(localExposeRect)), UseTransforms).boundingBox());
   1319 }
   1320 
   1321 void RenderLayerScrollableArea::updateScrollableAreaSet(bool hasOverflow)
   1322 {
   1323     Frame* frame = m_box->frame();
   1324     if (!frame)
   1325         return;
   1326 
   1327     FrameView* frameView = frame->view();
   1328     if (!frameView)
   1329         return;
   1330 
   1331     bool isVisibleToHitTest = m_box->visibleToHitTesting();
   1332     if (HTMLFrameOwnerElement* owner = frame->ownerElement())
   1333         isVisibleToHitTest &= owner->renderer() && owner->renderer()->visibleToHitTesting();
   1334 
   1335     bool requiresScrollableArea = hasOverflow && isVisibleToHitTest;
   1336     bool updatedScrollableAreaSet = false;
   1337     if (requiresScrollableArea) {
   1338         if (frameView->addScrollableArea(this))
   1339             updatedScrollableAreaSet = true;
   1340     } else {
   1341         if (frameView->removeScrollableArea(this))
   1342             updatedScrollableAreaSet = true;
   1343     }
   1344 
   1345     if (updatedScrollableAreaSet) {
   1346         // Count the total number of RenderLayers that are scrollable areas for
   1347         // any period. We only want to record this at most once per RenderLayer.
   1348         if (requiresScrollableArea && !m_isScrollableAreaHasBeenRecorded) {
   1349             blink::Platform::current()->histogramEnumeration("Renderer.CompositedScrolling", RenderLayer::IsScrollableAreaBucket, RenderLayer::CompositedScrollingHistogramMax);
   1350             m_isScrollableAreaHasBeenRecorded = true;
   1351         }
   1352 
   1353         // We always want composited scrolling if compositor driven accelerated
   1354         // scrolling is enabled. Since we will not update needs composited scrolling
   1355         // in this case, we must force our state to update.
   1356         if (layer()->compositorDrivenAcceleratedScrollingEnabled())
   1357             layer()->didUpdateNeedsCompositedScrolling();
   1358         else if (requiresScrollableArea)
   1359             m_box->view()->compositor()->setNeedsUpdateCompositingRequirementsState();
   1360         else
   1361             setNeedsCompositedScrolling(false);
   1362     }
   1363 }
   1364 
   1365 void RenderLayerScrollableArea::updateNeedsCompositedScrolling()
   1366 {
   1367     TRACE_EVENT0("comp-scroll", "RenderLayer::updateNeedsCompositedScrolling");
   1368 
   1369     layer()->stackingNode()->updateDescendantsAreContiguousInStackingOrder();
   1370     layer()->updateDescendantDependentFlags();
   1371 
   1372     ASSERT(scrollsOverflow());
   1373     const bool needsToBeStackingContainer = layer()->acceleratedCompositingForOverflowScrollEnabled()
   1374         && layer()->stackingNode()->descendantsAreContiguousInStackingOrder()
   1375         && !layer()->hasUnclippedDescendant();
   1376 
   1377     const bool needsToBeStackingContainerDidChange = layer()->stackingNode()->setNeedsToBeStackingContainer(needsToBeStackingContainer);
   1378 
   1379     const bool needsCompositedScrolling = needsToBeStackingContainer
   1380         || layer()->compositorDrivenAcceleratedScrollingEnabled();
   1381 
   1382     // We gather a boolean value for use with Google UMA histograms to
   1383     // quantify the actual effects of a set of patches attempting to
   1384     // relax composited scrolling requirements, thereby increasing the
   1385     // number of composited overflow divs.
   1386     if (layer()->acceleratedCompositingForOverflowScrollEnabled())
   1387         blink::Platform::current()->histogramEnumeration("Renderer.NeedsCompositedScrolling", needsCompositedScrolling, 2);
   1388 
   1389     const bool needsCompositedScrollingDidChange = setNeedsCompositedScrolling(needsCompositedScrolling);
   1390 
   1391     if (needsToBeStackingContainerDidChange || needsCompositedScrollingDidChange) {
   1392         // Note, the z-order lists may need to be rebuilt, but our code guarantees
   1393         // that we have not affected stacking, so we will not dirty
   1394         // m_descendantsAreContiguousInStackingOrder for either us or our stacking
   1395         // context or container.
   1396         layer()->didUpdateNeedsCompositedScrolling();
   1397     }
   1398 }
   1399 
   1400 bool RenderLayerScrollableArea::setNeedsCompositedScrolling(bool needsCompositedScrolling)
   1401 {
   1402     if (this->needsCompositedScrolling() == needsCompositedScrolling)
   1403         return false;
   1404 
   1405     // Count the total number of RenderLayers which need composited scrolling at
   1406     // some point. This should be recorded at most once per RenderLayer, so we
   1407     // check m_willUseCompositedScrollingHasBeenRecorded.
   1408     if (layer()->acceleratedCompositingForOverflowScrollEnabled() && !m_willUseCompositedScrollingHasBeenRecorded) {
   1409         blink::Platform::current()->histogramEnumeration("Renderer.CompositedScrolling", RenderLayer::WillUseCompositedScrollingBucket, RenderLayer::CompositedScrollingHistogramMax);
   1410         m_willUseCompositedScrollingHasBeenRecorded = true;
   1411     }
   1412 
   1413     m_needsCompositedScrolling = needsCompositedScrolling;
   1414 
   1415     return true;
   1416 }
   1417 
   1418 void RenderLayerScrollableArea::updateHasVisibleNonLayerContent()
   1419 {
   1420     layer()->updateHasVisibleNonLayerContent();
   1421 }
   1422 
   1423 void RenderLayerScrollableArea::updateCompositingLayersAfterScroll()
   1424 {
   1425     RenderLayerCompositor* compositor = m_box->view()->compositor();
   1426     if (compositor->inCompositingMode()) {
   1427         // FIXME: Our stacking container is guaranteed to contain all of our descendants that may need
   1428         // repositioning, so we should be able to enqueue a partial update compositing layers from there.
   1429         // this feature was overridden for now by deferred compositing updates.
   1430         if (usesCompositedScrolling())
   1431             compositor->updateCompositingLayers(CompositingUpdateOnCompositedScroll);
   1432         else
   1433             compositor->updateCompositingLayers(CompositingUpdateOnScroll);
   1434     }
   1435 }
   1436 
   1437 bool RenderLayerScrollableArea::usesCompositedScrolling() const
   1438 {
   1439     // Scroll form controls on the main thread so they exhibit correct touch scroll event bubbling
   1440     if (m_box && (m_box->isIntristicallyScrollable(VerticalScrollbar) || m_box->isIntristicallyScrollable(HorizontalScrollbar)))
   1441         return false;
   1442 
   1443     return m_box->hasCompositedLayerMapping() && m_box->compositedLayerMapping()->scrollingLayer();
   1444 }
   1445 
   1446 bool RenderLayerScrollableArea::adjustForForceCompositedScrollingMode(bool value) const
   1447 {
   1448     switch (m_forceNeedsCompositedScrolling) {
   1449     case DoNotForceCompositedScrolling:
   1450         return value;
   1451     case CompositedScrollingAlwaysOn:
   1452         return true;
   1453     case CompositedScrollingAlwaysOff:
   1454         return false;
   1455     }
   1456 
   1457     ASSERT_NOT_REACHED();
   1458     return value;
   1459 }
   1460 
   1461 bool RenderLayerScrollableArea::needsCompositedScrolling() const
   1462 {
   1463     return adjustForForceCompositedScrollingMode(m_needsCompositedScrolling);
   1464 }
   1465 
   1466 void RenderLayerScrollableArea::setForceNeedsCompositedScrolling(ForceNeedsCompositedScrollingMode mode)
   1467 {
   1468     if (m_forceNeedsCompositedScrolling == mode)
   1469         return;
   1470 
   1471     m_forceNeedsCompositedScrolling = mode;
   1472     layer()->didUpdateNeedsCompositedScrolling();
   1473 }
   1474 
   1475 } // Namespace WebCore
   1476