Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(361)

Side by Side Diff: Source/core/rendering/RenderLayerScrollableArea.cpp

Issue 898783003: Move rendering/RenderLayer* to layout/ (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: Created 5 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
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@fas.harvard.edu>
9 * Christian Biesinger <cbiesinger@web.de>
10 * Randall Jesup <rjesup@wgate.com>
11 * Roland Mainz <roland.mainz@informatik.med.uni-giessen.de>
12 * Josh Soref <timeless@mac.com>
13 * Boris Zbarsky <bzbarsky@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 US A
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/AXObjectCache.h"
49 #include "core/dom/Node.h"
50 #include "core/dom/shadow/ShadowRoot.h"
51 #include "core/editing/FrameSelection.h"
52 #include "core/frame/FrameView.h"
53 #include "core/frame/LocalFrame.h"
54 #include "core/frame/Settings.h"
55 #include "core/html/HTMLFrameOwnerElement.h"
56 #include "core/inspector/InspectorInstrumentation.h"
57 #include "core/layout/LayoutTheme.h"
58 #include "core/layout/compositing/CompositedLayerMapping.h"
59 #include "core/layout/compositing/RenderLayerCompositor.h"
60 #include "core/page/Chrome.h"
61 #include "core/page/EventHandler.h"
62 #include "core/page/FocusController.h"
63 #include "core/page/Page.h"
64 #include "core/page/scrolling/ScrollingCoordinator.h"
65 #include "core/rendering/RenderGeometryMap.h"
66 #include "core/rendering/RenderScrollbar.h"
67 #include "core/rendering/RenderScrollbarPart.h"
68 #include "core/rendering/RenderView.h"
69 #include "platform/PlatformGestureEvent.h"
70 #include "platform/PlatformMouseEvent.h"
71 #include "platform/graphics/GraphicsContextStateSaver.h"
72 #include "platform/graphics/GraphicsLayer.h"
73 #include "platform/graphics/paint/DrawingRecorder.h"
74 #include "platform/scroll/ScrollAnimator.h"
75 #include "platform/scroll/ScrollbarTheme.h"
76 #include "public/platform/Platform.h"
77
78 namespace blink {
79
80 const int ResizerControlExpandRatioForTouch = 2;
81
82 RenderLayerScrollableArea::RenderLayerScrollableArea(RenderLayer& layer)
83 : m_layer(layer)
84 , m_inResizeMode(false)
85 , m_scrollsOverflow(false)
86 , m_scrollDimensionsDirty(true)
87 , m_inOverflowRelayout(false)
88 , m_nextTopmostScrollChild(0)
89 , m_topmostScrollChild(0)
90 , m_needsCompositedScrolling(false)
91 , m_scrollCorner(nullptr)
92 , m_resizer(nullptr)
93 {
94 ScrollableArea::setConstrainsScrollingToContentEdge(false);
95
96 Node* node = box().node();
97 if (node && node->isElementNode()) {
98 // We save and restore only the scrollOffset as the other scroll values are recalculated.
99 Element* element = toElement(node);
100 m_scrollOffset = element->savedLayerScrollOffset();
101 if (!m_scrollOffset.isZero())
102 scrollAnimator()->setCurrentPosition(FloatPoint(m_scrollOffset.width (), m_scrollOffset.height()));
103 element->setSavedLayerScrollOffset(IntSize());
104 }
105
106 updateResizerAreaSet();
107 }
108
109 RenderLayerScrollableArea::~RenderLayerScrollableArea()
110 {
111 if (inResizeMode() && !box().documentBeingDestroyed()) {
112 if (LocalFrame* frame = box().frame())
113 frame->eventHandler().resizeScrollableAreaDestroyed();
114 }
115
116 if (LocalFrame* frame = box().frame()) {
117 if (FrameView* frameView = frame->view()) {
118 frameView->removeScrollableArea(this);
119 frameView->removeAnimatingScrollableArea(this);
120 }
121 }
122
123 if (box().frame() && box().frame()->page()) {
124 if (ScrollingCoordinator* scrollingCoordinator = box().frame()->page()-> scrollingCoordinator())
125 scrollingCoordinator->willDestroyScrollableArea(this);
126 }
127
128 if (!box().documentBeingDestroyed()) {
129 Node* node = box().node();
130 // FIXME: Make setSavedLayerScrollOffset take DoubleSize. crbug.com/4142 83.
131 if (node && node->isElementNode())
132 toElement(node)->setSavedLayerScrollOffset(flooredIntSize(m_scrollOf fset));
133 }
134
135 if (LocalFrame* frame = box().frame()) {
136 if (FrameView* frameView = frame->view())
137 frameView->removeResizerArea(box());
138 }
139
140 destroyScrollbar(HorizontalScrollbar);
141 destroyScrollbar(VerticalScrollbar);
142
143 if (m_scrollCorner)
144 m_scrollCorner->destroy();
145 if (m_resizer)
146 m_resizer->destroy();
147 }
148
149 HostWindow* RenderLayerScrollableArea::hostWindow() const
150 {
151 if (Page* page = box().frame()->page())
152 return &page->chrome();
153 return nullptr;
154 }
155
156 GraphicsLayer* RenderLayerScrollableArea::layerForScrolling() const
157 {
158 return layer()->hasCompositedLayerMapping() ? layer()->compositedLayerMappin g()->scrollingContentsLayer() : 0;
159 }
160
161 GraphicsLayer* RenderLayerScrollableArea::layerForHorizontalScrollbar() const
162 {
163 // See crbug.com/343132.
164 DisableCompositingQueryAsserts disabler;
165
166 return layer()->hasCompositedLayerMapping() ? layer()->compositedLayerMappin g()->layerForHorizontalScrollbar() : 0;
167 }
168
169 GraphicsLayer* RenderLayerScrollableArea::layerForVerticalScrollbar() const
170 {
171 // See crbug.com/343132.
172 DisableCompositingQueryAsserts disabler;
173
174 return layer()->hasCompositedLayerMapping() ? layer()->compositedLayerMappin g()->layerForVerticalScrollbar() : 0;
175 }
176
177 GraphicsLayer* RenderLayerScrollableArea::layerForScrollCorner() const
178 {
179 // See crbug.com/343132.
180 DisableCompositingQueryAsserts disabler;
181
182 return layer()->hasCompositedLayerMapping() ? layer()->compositedLayerMappin g()->layerForScrollCorner() : 0;
183 }
184
185 void RenderLayerScrollableArea::invalidateScrollbarRect(Scrollbar* scrollbar, co nst IntRect& rect)
186 {
187 // See crbug.com/343132.
188 DisableCompositingQueryAsserts disabler;
189
190 if (scrollbar == m_vBar.get()) {
191 if (GraphicsLayer* layer = layerForVerticalScrollbar()) {
192 layer->setNeedsDisplayInRect(rect, PaintInvalidationScroll);
193 return;
194 }
195 } else {
196 if (GraphicsLayer* layer = layerForHorizontalScrollbar()) {
197 layer->setNeedsDisplayInRect(rect, PaintInvalidationScroll);
198 return;
199 }
200 }
201
202 IntRect scrollRect = rect;
203 // If we are not yet inserted into the tree, there is no need to issue paint invaldiations.
204 if (!box().isRenderView() && !box().parent())
205 return;
206
207 if (scrollbar == m_vBar.get())
208 scrollRect.move(verticalScrollbarStart(0, box().size().width()), box().b orderTop());
209 else
210 scrollRect.move(horizontalScrollbarStart(0), box().size().height() - box ().borderBottom() - scrollbar->height());
211
212 if (scrollRect.isEmpty())
213 return;
214
215 LayoutRect paintInvalidationRect = scrollRect;
216 box().flipForWritingMode(paintInvalidationRect);
217
218 IntRect intRect = pixelSnappedIntRect(paintInvalidationRect);
219
220 if (box().frameView()->isInPerformLayout())
221 addScrollbarDamage(scrollbar, intRect);
222 else
223 box().invalidatePaintRectangle(intRect);
224 }
225
226 void RenderLayerScrollableArea::invalidateScrollCornerRect(const IntRect& rect)
227 {
228 if (GraphicsLayer* layer = layerForScrollCorner()) {
229 layer->setNeedsDisplayInRect(rect, PaintInvalidationScroll);
230 return;
231 }
232
233 if (m_scrollCorner)
234 m_scrollCorner->invalidatePaintRectangle(rect);
235 if (m_resizer)
236 m_resizer->invalidatePaintRectangle(rect);
237 }
238
239 bool RenderLayerScrollableArea::shouldUseIntegerScrollOffset() const
240 {
241 Frame* frame = box().frame();
242 if (frame->settings() && !frame->settings()->preferCompositingToLCDTextEnabl ed())
243 return true;
244 return false;
245 }
246
247 bool RenderLayerScrollableArea::isActive() const
248 {
249 Page* page = box().frame()->page();
250 return page && page->focusController().isActive();
251 }
252
253 bool RenderLayerScrollableArea::isScrollCornerVisible() const
254 {
255 return !scrollCornerRect().isEmpty();
256 }
257
258 static int cornerStart(const RenderStyle* style, int minX, int maxX, int thickne ss)
259 {
260 if (style->shouldPlaceBlockDirectionScrollbarOnLogicalLeft())
261 return minX + style->borderLeftWidth();
262 return maxX - thickness - style->borderRightWidth();
263 }
264
265 static IntRect cornerRect(const RenderStyle* style, const Scrollbar* horizontalS crollbar, const Scrollbar* verticalScrollbar, const IntRect& bounds)
266 {
267 int horizontalThickness;
268 int verticalThickness;
269 if (!verticalScrollbar && !horizontalScrollbar) {
270 // FIXME: This isn't right. We need to know the thickness of custom scro llbars
271 // even when they don't exist in order to set the resizer square size pr operly.
272 horizontalThickness = ScrollbarTheme::theme()->scrollbarThickness();
273 verticalThickness = horizontalThickness;
274 } else if (verticalScrollbar && !horizontalScrollbar) {
275 horizontalThickness = verticalScrollbar->width();
276 verticalThickness = horizontalThickness;
277 } else if (horizontalScrollbar && !verticalScrollbar) {
278 verticalThickness = horizontalScrollbar->height();
279 horizontalThickness = verticalThickness;
280 } else {
281 horizontalThickness = verticalScrollbar->width();
282 verticalThickness = horizontalScrollbar->height();
283 }
284 return IntRect(cornerStart(style, bounds.x(), bounds.maxX(), horizontalThick ness),
285 bounds.maxY() - verticalThickness - style->borderBottomWidth(),
286 horizontalThickness, verticalThickness);
287 }
288
289
290 IntRect RenderLayerScrollableArea::scrollCornerRect() const
291 {
292 // We have a scrollbar corner when a scrollbar is visible and not filling th e entire length of the box.
293 // This happens when:
294 // (a) A resizer is present and at least one scrollbar is present
295 // (b) Both scrollbars are present.
296 bool hasHorizontalBar = horizontalScrollbar();
297 bool hasVerticalBar = verticalScrollbar();
298 bool hasResizer = box().style()->resize() != RESIZE_NONE;
299 if ((hasHorizontalBar && hasVerticalBar) || (hasResizer && (hasHorizontalBar || hasVerticalBar)))
300 return cornerRect(box().style(), horizontalScrollbar(), verticalScrollba r(), box().pixelSnappedBorderBoxRect());
301 return IntRect();
302 }
303
304 IntRect RenderLayerScrollableArea::convertFromScrollbarToContainingView(const Sc rollbar* scrollbar, const IntRect& scrollbarRect) const
305 {
306 RenderView* view = box().view();
307 if (!view)
308 return scrollbarRect;
309
310 IntRect rect = scrollbarRect;
311 rect.move(scrollbarOffset(scrollbar));
312
313 return view->frameView()->convertFromRenderer(box(), rect);
314 }
315
316 IntRect RenderLayerScrollableArea::convertFromContainingViewToScrollbar(const Sc rollbar* scrollbar, const IntRect& parentRect) const
317 {
318 RenderView* view = box().view();
319 if (!view)
320 return parentRect;
321
322 IntRect rect = view->frameView()->convertToRenderer(box(), parentRect);
323 rect.move(-scrollbarOffset(scrollbar));
324 return rect;
325 }
326
327 IntPoint RenderLayerScrollableArea::convertFromScrollbarToContainingView(const S crollbar* scrollbar, const IntPoint& scrollbarPoint) const
328 {
329 RenderView* view = box().view();
330 if (!view)
331 return scrollbarPoint;
332
333 IntPoint point = scrollbarPoint;
334 point.move(scrollbarOffset(scrollbar));
335 return view->frameView()->convertFromRenderer(box(), point);
336 }
337
338 IntPoint RenderLayerScrollableArea::convertFromContainingViewToScrollbar(const S crollbar* scrollbar, const IntPoint& parentPoint) const
339 {
340 RenderView* view = box().view();
341 if (!view)
342 return parentPoint;
343
344 IntPoint point = view->frameView()->convertToRenderer(box(), parentPoint);
345
346 point.move(-scrollbarOffset(scrollbar));
347 return point;
348 }
349
350 int RenderLayerScrollableArea::scrollSize(ScrollbarOrientation orientation) cons t
351 {
352 IntSize scrollDimensions = maximumScrollPosition() - minimumScrollPosition() ;
353 return (orientation == HorizontalScrollbar) ? scrollDimensions.width() : scr ollDimensions.height();
354 }
355
356 void RenderLayerScrollableArea::setScrollOffset(const IntPoint& newScrollOffset)
357 {
358 setScrollOffset(DoublePoint(newScrollOffset));
359 }
360
361 void RenderLayerScrollableArea::setScrollOffset(const DoublePoint& newScrollOffs et)
362 {
363 // Ensure that the dimensions will be computed if they need to be (for overf low:hidden blocks).
364 if (m_scrollDimensionsDirty)
365 computeScrollDimensions();
366
367 if (scrollOffset() == toDoubleSize(newScrollOffset))
368 return;
369
370 m_scrollOffset = toDoubleSize(newScrollOffset);
371
372 LocalFrame* frame = box().frame();
373 ASSERT(frame);
374
375 RefPtrWillBeRawPtr<FrameView> frameView = box().frameView();
376
377 TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "ScrollLayer", "data", InspectorScrollLayerEvent::data(&box()));
378 // FIXME(361045): remove InspectorInstrumentation calls once DevTools Timeli ne migrates to tracing.
379 InspectorInstrumentation::willScrollLayer(&box());
380
381 // Update the positions of our child layers (if needed as only fixed layers should be impacted by a scroll).
382 // We don't update compositing layers, because we need to do a deep update f rom the compositing ancestor.
383 if (!frameView->isInPerformLayout()) {
384 // If we're in the middle of layout, we'll just update layers once layou t has finished.
385 layer()->updateLayerPositionsAfterOverflowScroll();
386 // Update regions, scrolling may change the clip of a particular region.
387 frameView->updateAnnotatedRegions();
388 frameView->setNeedsUpdateWidgetPositions();
389 updateCompositingLayersAfterScroll();
390 }
391
392 const RenderLayerModelObject* paintInvalidationContainer = box().containerFo rPaintInvalidation();
393 // The caret rect needs to be invalidated after scrolling
394 frame->selection().setCaretRectNeedsUpdate();
395
396 FloatQuad quadForFakeMouseMoveEvent = FloatQuad(layer()->renderer()->previou sPaintInvalidationRect());
397
398 quadForFakeMouseMoveEvent = paintInvalidationContainer->localToAbsoluteQuad( quadForFakeMouseMoveEvent);
399 frame->eventHandler().dispatchFakeMouseMoveEventSoonInQuad(quadForFakeMouseM oveEvent);
400
401 bool requiresPaintInvalidation = true;
402
403 {
404 // FIXME(420741): Since scrolling depends on compositing state, the scro ll should be
405 // deferred until after the compositing update.
406 DisableCompositingQueryAsserts disabler;
407 if (box().view()->compositor()->inCompositingMode()) {
408 bool onlyScrolledCompositedLayers = scrollsOverflow()
409 && !layer()->hasVisibleNonLayerContent()
410 && !layer()->hasNonCompositedChild()
411 && !layer()->hasBlockSelectionGapBounds()
412 && box().style()->backgroundLayers().attachment() != LocalBackgr oundAttachment;
413
414 if (usesCompositedScrolling() || onlyScrolledCompositedLayers)
415 requiresPaintInvalidation = false;
416 }
417 }
418
419 // Just schedule a full paint invalidation of our object.
420 if (requiresPaintInvalidation)
421 box().setShouldDoFullPaintInvalidation();
422
423 // Schedule the scroll DOM event.
424 if (box().node())
425 box().node()->document().enqueueScrollEventForNode(box().node());
426
427 if (AXObjectCache* cache = box().document().existingAXObjectCache())
428 cache->handleScrollPositionChanged(&box());
429
430 InspectorInstrumentation::didScrollLayer(&box());
431 }
432
433 IntPoint RenderLayerScrollableArea::scrollPosition() const
434 {
435 return IntPoint(flooredIntSize(m_scrollOffset));
436 }
437
438 DoublePoint RenderLayerScrollableArea::scrollPositionDouble() const
439 {
440 return DoublePoint(m_scrollOffset);
441 }
442
443 IntPoint RenderLayerScrollableArea::minimumScrollPosition() const
444 {
445 return -scrollOrigin();
446 }
447
448 IntPoint RenderLayerScrollableArea::maximumScrollPosition() const
449 {
450 if (!box().hasOverflowClip())
451 return -scrollOrigin();
452 return -scrollOrigin() + IntPoint(pixelSnappedScrollWidth(), pixelSnappedScr ollHeight()) - enclosingIntRect(box().clientBoxRect()).size();
453 }
454
455 IntRect RenderLayerScrollableArea::visibleContentRect(IncludeScrollbarsInRect sc rollbarInclusion) const
456 {
457 int verticalScrollbarWidth = 0;
458 int horizontalScrollbarHeight = 0;
459 if (scrollbarInclusion == IncludeScrollbars) {
460 verticalScrollbarWidth = (verticalScrollbar() && !verticalScrollbar()->i sOverlayScrollbar()) ? verticalScrollbar()->width() : 0;
461 horizontalScrollbarHeight = (horizontalScrollbar() && !horizontalScrollb ar()->isOverlayScrollbar()) ? horizontalScrollbar()->height() : 0;
462 }
463
464 return IntRect(IntPoint(scrollXOffset(), scrollYOffset()),
465 IntSize(max(0, layer()->size().width() - verticalScrollbarWidth), max(0, layer()->size().height() - horizontalScrollbarHeight)));
466 }
467
468 int RenderLayerScrollableArea::visibleHeight() const
469 {
470 return layer()->size().height();
471 }
472
473 int RenderLayerScrollableArea::visibleWidth() const
474 {
475 return layer()->size().width();
476 }
477
478 IntSize RenderLayerScrollableArea::contentsSize() const
479 {
480 return IntSize(scrollWidth(), scrollHeight());
481 }
482
483 IntSize RenderLayerScrollableArea::overhangAmount() const
484 {
485 return IntSize();
486 }
487
488 IntPoint RenderLayerScrollableArea::lastKnownMousePosition() const
489 {
490 return box().frame() ? box().frame()->eventHandler().lastKnownMousePosition( ) : IntPoint();
491 }
492
493 bool RenderLayerScrollableArea::shouldSuspendScrollAnimations() const
494 {
495 RenderView* view = box().view();
496 if (!view)
497 return true;
498 return view->frameView()->shouldSuspendScrollAnimations();
499 }
500
501 bool RenderLayerScrollableArea::scrollbarsCanBeActive() const
502 {
503 RenderView* view = box().view();
504 if (!view)
505 return false;
506 return view->frameView()->scrollbarsCanBeActive();
507 }
508
509 IntRect RenderLayerScrollableArea::scrollableAreaBoundingBox() const
510 {
511 return box().absoluteBoundingBoxRect();
512 }
513
514 void RenderLayerScrollableArea::registerForAnimation()
515 {
516 if (LocalFrame* frame = box().frame()) {
517 if (FrameView* frameView = frame->view())
518 frameView->addAnimatingScrollableArea(this);
519 }
520 }
521
522 void RenderLayerScrollableArea::deregisterForAnimation()
523 {
524 if (LocalFrame* frame = box().frame()) {
525 if (FrameView* frameView = frame->view())
526 frameView->removeAnimatingScrollableArea(this);
527 }
528 }
529
530 bool RenderLayerScrollableArea::userInputScrollable(ScrollbarOrientation orienta tion) const
531 {
532 if (box().isIntristicallyScrollable(orientation))
533 return true;
534
535 EOverflow overflowStyle = (orientation == HorizontalScrollbar) ?
536 box().style()->overflowX() : box().style()->overflowY();
537 return (overflowStyle == OSCROLL || overflowStyle == OAUTO || overflowStyle == OOVERLAY);
538 }
539
540 bool RenderLayerScrollableArea::shouldPlaceVerticalScrollbarOnLeft() const
541 {
542 return box().style()->shouldPlaceBlockDirectionScrollbarOnLogicalLeft();
543 }
544
545 int RenderLayerScrollableArea::pageStep(ScrollbarOrientation orientation) const
546 {
547 int length = (orientation == HorizontalScrollbar) ?
548 box().pixelSnappedClientWidth() : box().pixelSnappedClientHeight();
549 int minPageStep = static_cast<float>(length) * ScrollableArea::minFractionTo StepWhenPaging();
550 int pageStep = max(minPageStep, length - ScrollableArea::maxOverlapBetweenPa ges());
551
552 return max(pageStep, 1);
553 }
554
555 RenderBox& RenderLayerScrollableArea::box() const
556 {
557 return *m_layer.renderBox();
558 }
559
560 RenderLayer* RenderLayerScrollableArea::layer() const
561 {
562 return &m_layer;
563 }
564
565 LayoutUnit RenderLayerScrollableArea::scrollWidth() const
566 {
567 if (m_scrollDimensionsDirty)
568 const_cast<RenderLayerScrollableArea*>(this)->computeScrollDimensions();
569 return m_overflowRect.width();
570 }
571
572 LayoutUnit RenderLayerScrollableArea::scrollHeight() const
573 {
574 if (m_scrollDimensionsDirty)
575 const_cast<RenderLayerScrollableArea*>(this)->computeScrollDimensions();
576 return m_overflowRect.height();
577 }
578
579 int RenderLayerScrollableArea::pixelSnappedScrollWidth() const
580 {
581 return snapSizeToPixel(scrollWidth(), box().clientLeft() + box().location(). x());
582 }
583
584 int RenderLayerScrollableArea::pixelSnappedScrollHeight() const
585 {
586 return snapSizeToPixel(scrollHeight(), box().clientTop() + box().location(). y());
587 }
588
589 void RenderLayerScrollableArea::computeScrollDimensions()
590 {
591 m_scrollDimensionsDirty = false;
592
593 m_overflowRect = box().layoutOverflowRect();
594 box().flipForWritingMode(m_overflowRect);
595
596 int scrollableLeftOverflow = m_overflowRect.x() - box().borderLeft() - (box( ).style()->shouldPlaceBlockDirectionScrollbarOnLogicalLeft() ? box().verticalScr ollbarWidth() : 0);
597 int scrollableTopOverflow = m_overflowRect.y() - box().borderTop();
598 setScrollOrigin(IntPoint(-scrollableLeftOverflow, -scrollableTopOverflow));
599 }
600
601 void RenderLayerScrollableArea::scrollToOffset(const DoubleSize& scrollOffset, S crollOffsetClamping clamp, ScrollBehavior scrollBehavior)
602 {
603 cancelProgrammaticScrollAnimation();
604 DoubleSize newScrollOffset = clamp == ScrollOffsetClamped ? clampScrollOffse t(scrollOffset) : scrollOffset;
605 if (newScrollOffset != adjustedScrollOffset()) {
606 if (scrollBehavior == ScrollBehaviorAuto)
607 scrollBehavior = box().style()->scrollBehavior();
608 DoublePoint origin(scrollOrigin());
609 if (scrollBehavior == ScrollBehaviorSmooth) {
610 // FIXME: Make programmaticallyScrollSmoothlyToOffset take DoublePoi nt. crbug.com/243871.
611 programmaticallyScrollSmoothlyToOffset(toFloatPoint(-origin + newScr ollOffset));
612 } else {
613 // FIXME: Make scrollToOffsetWithoutAnimation take DoublePoint. crbu g.com/414283.
614 scrollToOffsetWithoutAnimation(toFloatPoint(-origin + newScrollOffse t));
615 }
616 }
617 }
618
619 void RenderLayerScrollableArea::updateAfterLayout()
620 {
621 m_scrollDimensionsDirty = true;
622 DoubleSize originalScrollOffset = adjustedScrollOffset();
623
624 computeScrollDimensions();
625
626 // Layout may cause us to be at an invalid scroll position. In this case we need
627 // to pull our scroll offsets back to the max (or push them up to the min).
628 DoubleSize clampedScrollOffset = clampScrollOffset(adjustedScrollOffset());
629 if (clampedScrollOffset != adjustedScrollOffset())
630 scrollToOffset(clampedScrollOffset);
631
632 if (originalScrollOffset != adjustedScrollOffset()) {
633 DoublePoint origin(scrollOrigin());
634 scrollToOffsetWithoutAnimation(toFloatPoint(-origin + adjustedScrollOffs et()));
635 }
636
637 bool hasHorizontalOverflow = this->hasHorizontalOverflow();
638 bool hasVerticalOverflow = this->hasVerticalOverflow();
639
640 {
641 // Hits in compositing/overflow/automatically-opt-into-composited-scroll ing-after-style-change.html.
642 DisableCompositingQueryAsserts disabler;
643
644 // overflow:scroll should just enable/disable.
645 if (box().style()->overflowX() == OSCROLL && horizontalScrollbar())
646 horizontalScrollbar()->setEnabled(hasHorizontalOverflow);
647 if (box().style()->overflowY() == OSCROLL && verticalScrollbar())
648 verticalScrollbar()->setEnabled(hasVerticalOverflow);
649 }
650 if (hasOverlayScrollbars()) {
651 if (!scrollSize(HorizontalScrollbar))
652 setHasHorizontalScrollbar(false);
653 if (!scrollSize(VerticalScrollbar))
654 setHasVerticalScrollbar(false);
655 }
656 // overflow:auto may need to lay out again if scrollbars got added/removed.
657 bool autoHorizontalScrollBarChanged = box().hasAutoHorizontalScrollbar() && (hasHorizontalScrollbar() != hasHorizontalOverflow);
658 bool autoVerticalScrollBarChanged = box().hasAutoVerticalScrollbar() && (has VerticalScrollbar() != hasVerticalOverflow);
659
660 if (autoHorizontalScrollBarChanged || autoVerticalScrollBarChanged) {
661 if (box().hasAutoHorizontalScrollbar())
662 setHasHorizontalScrollbar(hasHorizontalOverflow);
663 if (box().hasAutoVerticalScrollbar())
664 setHasVerticalScrollbar(hasVerticalOverflow);
665
666 if (hasVerticalOverflow || hasHorizontalOverflow)
667 updateScrollCornerStyle();
668
669 layer()->updateSelfPaintingLayer();
670
671 // Force an update since we know the scrollbars have changed things.
672 if (box().document().hasAnnotatedRegions())
673 box().document().setAnnotatedRegionsDirty(true);
674
675 if (box().style()->overflowX() == OAUTO || box().style()->overflowY() == OAUTO) {
676 if (!m_inOverflowRelayout) {
677 // Our proprietary overflow: overlay value doesn't trigger a lay out.
678 m_inOverflowRelayout = true;
679 SubtreeLayoutScope layoutScope(box());
680 layoutScope.setNeedsLayout(&box());
681 if (box().isRenderBlock()) {
682 RenderBlock& block = toRenderBlock(box());
683 block.scrollbarsChanged(autoHorizontalScrollBarChanged, auto VerticalScrollBarChanged);
684 block.layoutBlock(true);
685 } else {
686 box().layout();
687 }
688 m_inOverflowRelayout = false;
689 }
690 }
691 }
692
693 {
694 // Hits in compositing/overflow/automatically-opt-into-composited-scroll ing-after-style-change.html.
695 DisableCompositingQueryAsserts disabler;
696
697 // Set up the range (and page step/line step).
698 if (Scrollbar* horizontalScrollbar = this->horizontalScrollbar()) {
699 int clientWidth = box().pixelSnappedClientWidth();
700 horizontalScrollbar->setProportion(clientWidth, overflowRect().width ());
701 }
702 if (Scrollbar* verticalScrollbar = this->verticalScrollbar()) {
703 int clientHeight = box().pixelSnappedClientHeight();
704 verticalScrollbar->setProportion(clientHeight, overflowRect().height ());
705 }
706 }
707
708 bool hasOverflow = hasScrollableHorizontalOverflow() || hasScrollableVertica lOverflow();
709 updateScrollableAreaSet(hasOverflow);
710
711 if (hasOverflow) {
712 DisableCompositingQueryAsserts disabler;
713 positionOverflowControls(IntSize());
714 }
715 }
716
717 bool RenderLayerScrollableArea::hasHorizontalOverflow() const
718 {
719 ASSERT(!m_scrollDimensionsDirty);
720
721 return pixelSnappedScrollWidth() > box().pixelSnappedClientWidth();
722 }
723
724 bool RenderLayerScrollableArea::hasVerticalOverflow() const
725 {
726 ASSERT(!m_scrollDimensionsDirty);
727
728 return pixelSnappedScrollHeight() > box().pixelSnappedClientHeight();
729 }
730
731 bool RenderLayerScrollableArea::hasScrollableHorizontalOverflow() const
732 {
733 return hasHorizontalOverflow() && box().scrollsOverflowX();
734 }
735
736 bool RenderLayerScrollableArea::hasScrollableVerticalOverflow() const
737 {
738 return hasVerticalOverflow() && box().scrollsOverflowY();
739 }
740
741 static bool overflowRequiresScrollbar(EOverflow overflow)
742 {
743 return overflow == OSCROLL;
744 }
745
746 static bool overflowDefinesAutomaticScrollbar(EOverflow overflow)
747 {
748 return overflow == OAUTO || overflow == OOVERLAY;
749 }
750
751 // This function returns true if the given box requires overflow scrollbars (as
752 // opposed to the 'viewport' scrollbars managed by the RenderLayerCompositor).
753 // FIXME: we should use the same scrolling machinery for both the viewport and
754 // overflow. Currently, we need to avoid producing scrollbars here if they'll be
755 // handled externally in the RLC.
756 static bool canHaveOverflowScrollbars(const RenderBox& box)
757 {
758 bool rootLayerScrolls = box.document().settings() && box.document().settings ()->rootLayerScrolls();
759 return (rootLayerScrolls || !box.isRenderView()) && box.document().viewportD efiningElement() != box.node();
760 }
761
762 void RenderLayerScrollableArea::updateAfterStyleChange(const RenderStyle* oldSty le)
763 {
764 if (!m_scrollDimensionsDirty)
765 updateScrollableAreaSet(hasScrollableHorizontalOverflow() || hasScrollab leVerticalOverflow());
766
767 if (!canHaveOverflowScrollbars(box()))
768 return;
769
770 EOverflow overflowX = box().style()->overflowX();
771 EOverflow overflowY = box().style()->overflowY();
772
773 // To avoid doing a relayout in updateScrollbarsAfterLayout, we try to keep any automatic scrollbar that was already present.
774 bool needsHorizontalScrollbar = (hasHorizontalScrollbar() && overflowDefines AutomaticScrollbar(overflowX)) || overflowRequiresScrollbar(overflowX);
775 bool needsVerticalScrollbar = (hasVerticalScrollbar() && overflowDefinesAuto maticScrollbar(overflowY)) || overflowRequiresScrollbar(overflowY);
776 setHasHorizontalScrollbar(needsHorizontalScrollbar);
777 setHasVerticalScrollbar(needsVerticalScrollbar);
778
779 // With overflow: scroll, scrollbars are always visible but may be disabled.
780 // When switching to another value, we need to re-enable them (see bug 11985 ).
781 if (needsHorizontalScrollbar && oldStyle && oldStyle->overflowX() == OSCROLL && overflowX != OSCROLL) {
782 ASSERT(hasHorizontalScrollbar());
783 m_hBar->setEnabled(true);
784 }
785
786 if (needsVerticalScrollbar && oldStyle && oldStyle->overflowY() == OSCROLL & & overflowY != OSCROLL) {
787 ASSERT(hasVerticalScrollbar());
788 m_vBar->setEnabled(true);
789 }
790
791 // FIXME: Need to detect a swap from custom to native scrollbars (and vice v ersa).
792 if (m_hBar)
793 m_hBar->styleChanged();
794 if (m_vBar)
795 m_vBar->styleChanged();
796
797 updateScrollCornerStyle();
798 updateResizerAreaSet();
799 updateResizerStyle();
800 }
801
802 bool RenderLayerScrollableArea::updateAfterCompositingChange()
803 {
804 layer()->updateScrollingStateAfterCompositingChange();
805 const bool layersChanged = m_topmostScrollChild != m_nextTopmostScrollChild;
806 m_topmostScrollChild = m_nextTopmostScrollChild;
807 m_nextTopmostScrollChild = nullptr;
808 return layersChanged;
809 }
810
811 void RenderLayerScrollableArea::updateAfterOverflowRecalc()
812 {
813 computeScrollDimensions();
814 if (Scrollbar* horizontalScrollbar = this->horizontalScrollbar()) {
815 int clientWidth = box().pixelSnappedClientWidth();
816 horizontalScrollbar->setProportion(clientWidth, overflowRect().width());
817 }
818 if (Scrollbar* verticalScrollbar = this->verticalScrollbar()) {
819 int clientHeight = box().pixelSnappedClientHeight();
820 verticalScrollbar->setProportion(clientHeight, overflowRect().height());
821 }
822
823 bool hasHorizontalOverflow = this->hasHorizontalOverflow();
824 bool hasVerticalOverflow = this->hasVerticalOverflow();
825 bool autoHorizontalScrollBarChanged = box().hasAutoHorizontalScrollbar() && (hasHorizontalScrollbar() != hasHorizontalOverflow);
826 bool autoVerticalScrollBarChanged = box().hasAutoVerticalScrollbar() && (has VerticalScrollbar() != hasVerticalOverflow);
827 if (autoHorizontalScrollBarChanged || autoVerticalScrollBarChanged)
828 box().setNeedsLayoutAndFullPaintInvalidation();
829 }
830
831 DoubleSize RenderLayerScrollableArea::clampScrollOffset(const DoubleSize& scroll Offset) const
832 {
833 int maxX = scrollWidth() - box().pixelSnappedClientWidth();
834 int maxY = scrollHeight() - box().pixelSnappedClientHeight();
835
836 double x = std::max(std::min(scrollOffset.width(), static_cast<double>(maxX) ), 0.0);
837 double y = std::max(std::min(scrollOffset.height(), static_cast<double>(maxY )), 0.0);
838 return DoubleSize(x, y);
839 }
840
841 IntRect RenderLayerScrollableArea::rectForHorizontalScrollbar(const IntRect& bor derBoxRect) const
842 {
843 if (!m_hBar)
844 return IntRect();
845
846 const IntRect& scrollCorner = scrollCornerRect();
847
848 return IntRect(horizontalScrollbarStart(borderBoxRect.x()),
849 borderBoxRect.maxY() - box().borderBottom() - m_hBar->height(),
850 borderBoxRect.width() - (box().borderLeft() + box().borderRight()) - scr ollCorner.width(),
851 m_hBar->height());
852 }
853
854 IntRect RenderLayerScrollableArea::rectForVerticalScrollbar(const IntRect& borde rBoxRect) const
855 {
856 if (!m_vBar)
857 return IntRect();
858
859 const IntRect& scrollCorner = scrollCornerRect();
860
861 return IntRect(verticalScrollbarStart(borderBoxRect.x(), borderBoxRect.maxX( )),
862 borderBoxRect.y() + box().borderTop(),
863 m_vBar->width(),
864 borderBoxRect.height() - (box().borderTop() + box().borderBottom()) - sc rollCorner.height());
865 }
866
867 LayoutUnit RenderLayerScrollableArea::verticalScrollbarStart(int minX, int maxX) const
868 {
869 if (box().style()->shouldPlaceBlockDirectionScrollbarOnLogicalLeft())
870 return minX + box().borderLeft();
871 return maxX - box().borderRight() - m_vBar->width();
872 }
873
874 LayoutUnit RenderLayerScrollableArea::horizontalScrollbarStart(int minX) const
875 {
876 int x = minX + box().borderLeft();
877 if (box().style()->shouldPlaceBlockDirectionScrollbarOnLogicalLeft())
878 x += m_vBar ? m_vBar->width() : resizerCornerRect(box().pixelSnappedBord erBoxRect(), ResizerForPointer).width();
879 return x;
880 }
881
882 IntSize RenderLayerScrollableArea::scrollbarOffset(const Scrollbar* scrollbar) c onst
883 {
884 if (scrollbar == m_vBar.get())
885 return IntSize(verticalScrollbarStart(0, box().size().width()), box().bo rderTop());
886
887 if (scrollbar == m_hBar.get())
888 return IntSize(horizontalScrollbarStart(0), box().size().height() - box( ).borderBottom() - scrollbar->height());
889
890 ASSERT_NOT_REACHED();
891 return IntSize();
892 }
893
894 static inline RenderObject* rendererForScrollbar(RenderObject& renderer)
895 {
896 if (Node* node = renderer.node()) {
897 if (ShadowRoot* shadowRoot = node->containingShadowRoot()) {
898 if (shadowRoot->type() == ShadowRoot::UserAgentShadowRoot)
899 return shadowRoot->host()->renderer();
900 }
901 }
902
903 return &renderer;
904 }
905
906 PassRefPtrWillBeRawPtr<Scrollbar> RenderLayerScrollableArea::createScrollbar(Scr ollbarOrientation orientation)
907 {
908 RefPtrWillBeRawPtr<Scrollbar> widget = nullptr;
909 RenderObject* actualRenderer = rendererForScrollbar(box());
910 bool hasCustomScrollbarStyle = actualRenderer->isBox() && actualRenderer->st yle()->hasPseudoStyle(SCROLLBAR);
911 if (hasCustomScrollbarStyle) {
912 widget = RenderScrollbar::createCustomScrollbar(this, orientation, actua lRenderer->node());
913 } else {
914 ScrollbarControlSize scrollbarSize = RegularScrollbar;
915 if (actualRenderer->style()->hasAppearance())
916 scrollbarSize = LayoutTheme::theme().scrollbarControlSizeForPart(act ualRenderer->style()->appearance());
917 widget = Scrollbar::create(this, orientation, scrollbarSize);
918 if (orientation == HorizontalScrollbar)
919 didAddScrollbar(widget.get(), HorizontalScrollbar);
920 else
921 didAddScrollbar(widget.get(), VerticalScrollbar);
922 }
923 box().document().view()->addChild(widget.get());
924 return widget.release();
925 }
926
927 void RenderLayerScrollableArea::destroyScrollbar(ScrollbarOrientation orientatio n)
928 {
929 RefPtrWillBePersistent<Scrollbar>& scrollbar = orientation == HorizontalScro llbar ? m_hBar : m_vBar;
930 if (!scrollbar)
931 return;
932
933 if (!scrollbar->isCustomScrollbar())
934 willRemoveScrollbar(scrollbar.get(), orientation);
935
936 toFrameView(scrollbar->parent())->removeChild(scrollbar.get());
937 scrollbar->disconnectFromScrollableArea();
938 scrollbar = nullptr;
939 }
940
941 void RenderLayerScrollableArea::setHasHorizontalScrollbar(bool hasScrollbar)
942 {
943 if (hasScrollbar == hasHorizontalScrollbar())
944 return;
945
946 if (hasScrollbar) {
947 // This doesn't hit in any tests, but since the equivalent code in setHa sVerticalScrollbar
948 // does, presumably this code does as well.
949 DisableCompositingQueryAsserts disabler;
950 m_hBar = createScrollbar(HorizontalScrollbar);
951 } else {
952 if (!layerForHorizontalScrollbar())
953 m_hBar->invalidate();
954 // Otherwise we will remove the layer and just need recompositing.
955
956 destroyScrollbar(HorizontalScrollbar);
957 }
958
959 // Destroying or creating one bar can cause our scrollbar corner to come and go. We need to update the opposite scrollbar's style.
960 if (m_hBar)
961 m_hBar->styleChanged();
962 if (m_vBar)
963 m_vBar->styleChanged();
964
965 // Force an update since we know the scrollbars have changed things.
966 if (box().document().hasAnnotatedRegions())
967 box().document().setAnnotatedRegionsDirty(true);
968 }
969
970 void RenderLayerScrollableArea::setHasVerticalScrollbar(bool hasScrollbar)
971 {
972 if (hasScrollbar == hasVerticalScrollbar())
973 return;
974
975 if (hasScrollbar) {
976 // Hits in compositing/overflow/automatically-opt-into-composited-scroll ing-after-style-change.html
977 DisableCompositingQueryAsserts disabler;
978 m_vBar = createScrollbar(VerticalScrollbar);
979 } else {
980 if (!layerForVerticalScrollbar())
981 m_vBar->invalidate();
982 // Otherwise we will remove the layer and just need recompositing.
983
984 destroyScrollbar(VerticalScrollbar);
985 }
986
987 // Destroying or creating one bar can cause our scrollbar corner to come and go. We need to update the opposite scrollbar's style.
988 if (m_hBar)
989 m_hBar->styleChanged();
990 if (m_vBar)
991 m_vBar->styleChanged();
992
993 // Force an update since we know the scrollbars have changed things.
994 if (box().document().hasAnnotatedRegions())
995 box().document().setAnnotatedRegionsDirty(true);
996 }
997
998 int RenderLayerScrollableArea::verticalScrollbarWidth(OverlayScrollbarSizeReleva ncy relevancy) const
999 {
1000 if (!m_vBar || (m_vBar->isOverlayScrollbar() && (relevancy == IgnoreOverlayS crollbarSize || !m_vBar->shouldParticipateInHitTesting())))
1001 return 0;
1002 return m_vBar->width();
1003 }
1004
1005 int RenderLayerScrollableArea::horizontalScrollbarHeight(OverlayScrollbarSizeRel evancy relevancy) const
1006 {
1007 if (!m_hBar || (m_hBar->isOverlayScrollbar() && (relevancy == IgnoreOverlayS crollbarSize || !m_hBar->shouldParticipateInHitTesting())))
1008 return 0;
1009 return m_hBar->height();
1010 }
1011
1012 void RenderLayerScrollableArea::positionOverflowControls(const IntSize& offsetFr omRoot)
1013 {
1014 if (!hasScrollbar() && !box().canResize())
1015 return;
1016
1017 const IntRect borderBox = box().pixelSnappedBorderBoxRect();
1018 if (Scrollbar* verticalScrollbar = this->verticalScrollbar()) {
1019 IntRect vBarRect = rectForVerticalScrollbar(borderBox);
1020 vBarRect.move(offsetFromRoot);
1021 verticalScrollbar->setFrameRect(vBarRect);
1022 }
1023
1024 if (Scrollbar* horizontalScrollbar = this->horizontalScrollbar()) {
1025 IntRect hBarRect = rectForHorizontalScrollbar(borderBox);
1026 hBarRect.move(offsetFromRoot);
1027 horizontalScrollbar->setFrameRect(hBarRect);
1028 }
1029
1030 const IntRect& scrollCorner = scrollCornerRect();
1031 if (m_scrollCorner)
1032 m_scrollCorner->setFrameRect(scrollCorner);
1033
1034 if (m_resizer)
1035 m_resizer->setFrameRect(resizerCornerRect(borderBox, ResizerForPointer)) ;
1036
1037 // FIXME, this should eventually be removed, once we are certain that compos ited
1038 // controls get correctly positioned on a compositor update. For now, conser vatively
1039 // leaving this unchanged.
1040 if (layer()->hasCompositedLayerMapping())
1041 layer()->compositedLayerMapping()->positionOverflowControlsLayers(offset FromRoot);
1042 }
1043
1044 void RenderLayerScrollableArea::updateScrollCornerStyle()
1045 {
1046 if (!m_scrollCorner && !hasScrollbar())
1047 return;
1048 if (!m_scrollCorner && hasOverlayScrollbars())
1049 return;
1050
1051 RenderObject* actualRenderer = rendererForScrollbar(box());
1052 RefPtr<RenderStyle> corner = box().hasOverflowClip() ? actualRenderer->getUn cachedPseudoStyle(PseudoStyleRequest(SCROLLBAR_CORNER), actualRenderer->style()) : PassRefPtr<RenderStyle>(nullptr);
1053 if (corner) {
1054 if (!m_scrollCorner) {
1055 m_scrollCorner = RenderScrollbarPart::createAnonymous(&box().documen t());
1056 m_scrollCorner->setParent(&box());
1057 }
1058 m_scrollCorner->setStyle(corner.release());
1059 } else if (m_scrollCorner) {
1060 m_scrollCorner->destroy();
1061 m_scrollCorner = nullptr;
1062 }
1063 }
1064
1065 bool RenderLayerScrollableArea::hitTestOverflowControls(HitTestResult& result, c onst IntPoint& localPoint)
1066 {
1067 if (!hasScrollbar() && !box().canResize())
1068 return false;
1069
1070 IntRect resizeControlRect;
1071 if (box().style()->resize() != RESIZE_NONE) {
1072 resizeControlRect = resizerCornerRect(box().pixelSnappedBorderBoxRect(), ResizerForPointer);
1073 if (resizeControlRect.contains(localPoint))
1074 return true;
1075 }
1076
1077 int resizeControlSize = max(resizeControlRect.height(), 0);
1078 if (m_vBar && m_vBar->shouldParticipateInHitTesting()) {
1079 LayoutRect vBarRect(verticalScrollbarStart(0, box().size().width()),
1080 box().borderTop(),
1081 m_vBar->width(),
1082 box().size().height() - (box().borderTop() + box().borderBottom()) - (m_hBar ? m_hBar->height() : resizeControlSize));
1083 if (vBarRect.contains(localPoint)) {
1084 result.setScrollbar(m_vBar.get());
1085 return true;
1086 }
1087 }
1088
1089 resizeControlSize = max(resizeControlRect.width(), 0);
1090 if (m_hBar && m_hBar->shouldParticipateInHitTesting()) {
1091 LayoutRect hBarRect(horizontalScrollbarStart(0),
1092 box().size().height() - box().borderBottom() - m_hBar->height(),
1093 box().size().width() - (box().borderLeft() + box().borderRight()) - (m_vBar ? m_vBar->width() : resizeControlSize),
1094 m_hBar->height());
1095 if (hBarRect.contains(localPoint)) {
1096 result.setScrollbar(m_hBar.get());
1097 return true;
1098 }
1099 }
1100
1101 // FIXME: We should hit test the m_scrollCorner and pass it back through the result.
1102
1103 return false;
1104 }
1105
1106 IntRect RenderLayerScrollableArea::resizerCornerRect(const IntRect& bounds, Resi zerHitTestType resizerHitTestType) const
1107 {
1108 if (box().style()->resize() == RESIZE_NONE)
1109 return IntRect();
1110 IntRect corner = cornerRect(box().style(), horizontalScrollbar(), verticalSc rollbar(), bounds);
1111
1112 if (resizerHitTestType == ResizerForTouch) {
1113 // We make the resizer virtually larger for touch hit testing. With the
1114 // expanding ratio k = ResizerControlExpandRatioForTouch, we first move
1115 // the resizer rect (of width w & height h), by (-w * (k-1), -h * (k-1)) ,
1116 // then expand the rect by new_w/h = w/h * k.
1117 int expandRatio = ResizerControlExpandRatioForTouch - 1;
1118 corner.move(-corner.width() * expandRatio, -corner.height() * expandRati o);
1119 corner.expand(corner.width() * expandRatio, corner.height() * expandRati o);
1120 }
1121
1122 return corner;
1123 }
1124
1125 IntRect RenderLayerScrollableArea::scrollCornerAndResizerRect() const
1126 {
1127 IntRect scrollCornerAndResizer = scrollCornerRect();
1128 if (scrollCornerAndResizer.isEmpty())
1129 scrollCornerAndResizer = resizerCornerRect(box().pixelSnappedBorderBoxRe ct(), ResizerForPointer);
1130 return scrollCornerAndResizer;
1131 }
1132
1133 bool RenderLayerScrollableArea::isPointInResizeControl(const IntPoint& absoluteP oint, ResizerHitTestType resizerHitTestType) const
1134 {
1135 if (!box().canResize())
1136 return false;
1137
1138 IntPoint localPoint = roundedIntPoint(box().absoluteToLocal(absolutePoint, U seTransforms));
1139 IntRect localBounds(0, 0, box().pixelSnappedWidth(), box().pixelSnappedHeigh t());
1140 return resizerCornerRect(localBounds, resizerHitTestType).contains(localPoin t);
1141 }
1142
1143 bool RenderLayerScrollableArea::hitTestResizerInFragments(const LayerFragments& layerFragments, const HitTestLocation& hitTestLocation) const
1144 {
1145 if (!box().canResize())
1146 return false;
1147
1148 if (layerFragments.isEmpty())
1149 return false;
1150
1151 for (int i = layerFragments.size() - 1; i >= 0; --i) {
1152 const LayerFragment& fragment = layerFragments.at(i);
1153 if (fragment.backgroundRect.intersects(hitTestLocation) && resizerCorner Rect(pixelSnappedIntRect(fragment.layerBounds), ResizerForPointer).contains(hitT estLocation.roundedPoint()))
1154 return true;
1155 }
1156
1157 return false;
1158 }
1159
1160 void RenderLayerScrollableArea::updateResizerAreaSet()
1161 {
1162 LocalFrame* frame = box().frame();
1163 if (!frame)
1164 return;
1165 FrameView* frameView = frame->view();
1166 if (!frameView)
1167 return;
1168 if (box().canResize())
1169 frameView->addResizerArea(box());
1170 else
1171 frameView->removeResizerArea(box());
1172 }
1173
1174 void RenderLayerScrollableArea::updateResizerStyle()
1175 {
1176 if (!m_resizer && !box().canResize())
1177 return;
1178
1179 RenderObject* actualRenderer = rendererForScrollbar(box());
1180 RefPtr<RenderStyle> resizer = box().hasOverflowClip() ? actualRenderer->getU ncachedPseudoStyle(PseudoStyleRequest(RESIZER), actualRenderer->style()) : PassR efPtr<RenderStyle>(nullptr);
1181 if (resizer) {
1182 if (!m_resizer) {
1183 m_resizer = RenderScrollbarPart::createAnonymous(&box().document());
1184 m_resizer->setParent(&box());
1185 }
1186 m_resizer->setStyle(resizer.release());
1187 } else if (m_resizer) {
1188 m_resizer->destroy();
1189 m_resizer = nullptr;
1190 }
1191 }
1192
1193 IntSize RenderLayerScrollableArea::offsetFromResizeCorner(const IntPoint& absolu tePoint) const
1194 {
1195 // Currently the resize corner is either the bottom right corner or the bott om left corner.
1196 // FIXME: This assumes the location is 0, 0. Is this guaranteed to always be the case?
1197 IntSize elementSize = layer()->size();
1198 if (box().style()->shouldPlaceBlockDirectionScrollbarOnLogicalLeft())
1199 elementSize.setWidth(0);
1200 IntPoint resizerPoint = IntPoint(elementSize);
1201 IntPoint localPoint = roundedIntPoint(box().absoluteToLocal(absolutePoint, U seTransforms));
1202 return localPoint - resizerPoint;
1203 }
1204
1205 void RenderLayerScrollableArea::resize(const PlatformEvent& evt, const LayoutSiz e& oldOffset)
1206 {
1207 // FIXME: This should be possible on generated content but is not right now.
1208 if (!inResizeMode() || !box().canResize() || !box().node())
1209 return;
1210
1211 ASSERT(box().node()->isElementNode());
1212 Element* element = toElement(box().node());
1213
1214 Document& document = element->document();
1215
1216 IntPoint pos;
1217 const PlatformGestureEvent* gevt = 0;
1218
1219 switch (evt.type()) {
1220 case PlatformEvent::MouseMoved:
1221 if (!document.frame()->eventHandler().mousePressed())
1222 return;
1223 pos = static_cast<const PlatformMouseEvent*>(&evt)->position();
1224 break;
1225 case PlatformEvent::GestureScrollUpdate:
1226 pos = static_cast<const PlatformGestureEvent*>(&evt)->position();
1227 gevt = static_cast<const PlatformGestureEvent*>(&evt);
1228 pos = gevt->position();
1229 pos.move(gevt->deltaX(), gevt->deltaY());
1230 break;
1231 default:
1232 ASSERT_NOT_REACHED();
1233 }
1234
1235 float zoomFactor = box().style()->effectiveZoom();
1236
1237 IntSize newOffset = offsetFromResizeCorner(document.view()->windowToContents (pos));
1238 newOffset.setWidth(newOffset.width() / zoomFactor);
1239 newOffset.setHeight(newOffset.height() / zoomFactor);
1240
1241 LayoutSize currentSize = box().size();
1242 currentSize.scale(1 / zoomFactor);
1243 LayoutSize minimumSize = element->minimumSizeForResizing().shrunkTo(currentS ize);
1244 element->setMinimumSizeForResizing(minimumSize);
1245
1246 LayoutSize adjustedOldOffset = LayoutSize(oldOffset.width() / zoomFactor, ol dOffset.height() / zoomFactor);
1247 if (box().style()->shouldPlaceBlockDirectionScrollbarOnLogicalLeft()) {
1248 newOffset.setWidth(-newOffset.width());
1249 adjustedOldOffset.setWidth(-adjustedOldOffset.width());
1250 }
1251
1252 LayoutSize difference((currentSize + newOffset - adjustedOldOffset).expanded To(minimumSize) - currentSize);
1253
1254 bool isBoxSizingBorder = box().style()->boxSizing() == BORDER_BOX;
1255
1256 EResize resize = box().style()->resize();
1257 if (resize != RESIZE_VERTICAL && difference.width()) {
1258 if (element->isFormControlElement()) {
1259 // Make implicit margins from the theme explicit (see <http://bugs.w ebkit.org/show_bug.cgi?id=9547>).
1260 element->setInlineStyleProperty(CSSPropertyMarginLeft, box().marginL eft() / zoomFactor, CSSPrimitiveValue::CSS_PX);
1261 element->setInlineStyleProperty(CSSPropertyMarginRight, box().margin Right() / zoomFactor, CSSPrimitiveValue::CSS_PX);
1262 }
1263 LayoutUnit baseWidth = box().size().width() - (isBoxSizingBorder ? Layou tUnit() : box().borderAndPaddingWidth());
1264 baseWidth = baseWidth / zoomFactor;
1265 element->setInlineStyleProperty(CSSPropertyWidth, roundToInt(baseWidth + difference.width()), CSSPrimitiveValue::CSS_PX);
1266 }
1267
1268 if (resize != RESIZE_HORIZONTAL && difference.height()) {
1269 if (element->isFormControlElement()) {
1270 // Make implicit margins from the theme explicit (see <http://bugs.w ebkit.org/show_bug.cgi?id=9547>).
1271 element->setInlineStyleProperty(CSSPropertyMarginTop, box().marginTo p() / zoomFactor, CSSPrimitiveValue::CSS_PX);
1272 element->setInlineStyleProperty(CSSPropertyMarginBottom, box().margi nBottom() / zoomFactor, CSSPrimitiveValue::CSS_PX);
1273 }
1274 LayoutUnit baseHeight = box().size().height() - (isBoxSizingBorder ? Lay outUnit() : box().borderAndPaddingHeight());
1275 baseHeight = baseHeight / zoomFactor;
1276 element->setInlineStyleProperty(CSSPropertyHeight, roundToInt(baseHeight + difference.height()), CSSPrimitiveValue::CSS_PX);
1277 }
1278
1279 document.updateLayout();
1280
1281 // FIXME (Radar 4118564): We should also autoscroll the window as necessary to keep the point under the cursor in view.
1282 }
1283
1284 LayoutRect RenderLayerScrollableArea::exposeRect(const LayoutRect& rect, const S crollAlignment& alignX, const ScrollAlignment& alignY)
1285 {
1286 LayoutRect localExposeRect(box().absoluteToLocalQuad(FloatQuad(FloatRect(rec t)), UseTransforms).boundingBox());
1287 localExposeRect.move(-box().borderLeft(), -box().borderTop());
1288 LayoutRect layerBounds(0, 0, box().clientWidth(), box().clientHeight());
1289 LayoutRect r = ScrollAlignment::getRectToExpose(layerBounds, localExposeRect , alignX, alignY);
1290
1291 DoubleSize clampedScrollOffset = clampScrollOffset(adjustedScrollOffset() + roundedIntSize(r.location()));
1292 if (clampedScrollOffset == adjustedScrollOffset())
1293 return rect;
1294
1295 DoubleSize oldScrollOffset = adjustedScrollOffset();
1296 scrollToOffset(clampedScrollOffset);
1297 DoubleSize scrollOffsetDifference = adjustedScrollOffset() - oldScrollOffset ;
1298 localExposeRect.move(-LayoutSize(scrollOffsetDifference));
1299 return LayoutRect(box().localToAbsoluteQuad(FloatQuad(FloatRect(localExposeR ect)), UseTransforms).boundingBox());
1300 }
1301
1302 void RenderLayerScrollableArea::updateScrollableAreaSet(bool hasOverflow)
1303 {
1304 LocalFrame* frame = box().frame();
1305 if (!frame)
1306 return;
1307
1308 FrameView* frameView = frame->view();
1309 if (!frameView)
1310 return;
1311
1312 // FIXME: Does this need to be fixed later for OOPI?
1313 bool isVisibleToHitTest = box().visibleToHitTesting();
1314 if (HTMLFrameOwnerElement* owner = frame->deprecatedLocalOwner())
1315 isVisibleToHitTest &= owner->renderer() && owner->renderer()->visibleToH itTesting();
1316
1317 bool didScrollOverflow = m_scrollsOverflow;
1318
1319 m_scrollsOverflow = hasOverflow && isVisibleToHitTest;
1320 if (didScrollOverflow == scrollsOverflow())
1321 return;
1322
1323 if (m_scrollsOverflow) {
1324 ASSERT(canHaveOverflowScrollbars(box()));
1325 frameView->addScrollableArea(this);
1326 } else
1327 frameView->removeScrollableArea(this);
1328 }
1329
1330 void RenderLayerScrollableArea::updateCompositingLayersAfterScroll()
1331 {
1332 DisableCompositingQueryAsserts disabler;
1333 RenderLayerCompositor* compositor = box().view()->compositor();
1334 if (compositor->inCompositingMode()) {
1335 if (usesCompositedScrolling()) {
1336 ASSERT(layer()->hasCompositedLayerMapping());
1337 layer()->compositedLayerMapping()->setNeedsGraphicsLayerUpdate(Graph icsLayerUpdateSubtree);
1338 compositor->setNeedsCompositingUpdate(CompositingUpdateAfterGeometry Change);
1339 } else {
1340 layer()->setNeedsCompositingInputsUpdate();
1341 }
1342 }
1343 }
1344
1345 bool RenderLayerScrollableArea::usesCompositedScrolling() const
1346 {
1347 // Scroll form controls on the main thread so they exhibit correct touch scr oll event bubbling
1348 if (box().isIntristicallyScrollable(VerticalScrollbar) || box().isIntristica llyScrollable(HorizontalScrollbar))
1349 return false;
1350
1351 // See https://codereview.chromium.org/176633003/ for the tests that fail wi thout this disabler.
1352 DisableCompositingQueryAsserts disabler;
1353 return layer()->hasCompositedLayerMapping() && layer()->compositedLayerMappi ng()->scrollingLayer();
1354 }
1355
1356 static bool layerNeedsCompositedScrolling(RenderLayerScrollableArea::LCDTextMode mode, const RenderLayer* layer)
1357 {
1358 if (mode == RenderLayerScrollableArea::ConsiderLCDText && !layer->compositor ()->preferCompositingToLCDTextEnabled())
1359 return false;
1360
1361 return layer->scrollsOverflow()
1362 && !layer->hasDescendantWithClipPath()
1363 && !layer->hasAncestorWithClipPath()
1364 && !layer->renderer()->style()->hasBorderRadius();
1365 }
1366
1367 void RenderLayerScrollableArea::updateNeedsCompositedScrolling(LCDTextMode mode)
1368 {
1369 const bool needsCompositedScrolling = layerNeedsCompositedScrolling(mode, la yer());
1370 if (static_cast<bool>(m_needsCompositedScrolling) != needsCompositedScrollin g) {
1371 m_needsCompositedScrolling = needsCompositedScrolling;
1372 layer()->didUpdateNeedsCompositedScrolling();
1373 }
1374 }
1375
1376 void RenderLayerScrollableArea::setTopmostScrollChild(RenderLayer* scrollChild)
1377 {
1378 // We only want to track the topmost scroll child for scrollable areas with
1379 // overlay scrollbars.
1380 if (!hasOverlayScrollbars())
1381 return;
1382 m_nextTopmostScrollChild = scrollChild;
1383 }
1384
1385 } // namespace blink
OLDNEW
« no previous file with comments | « Source/core/rendering/RenderLayerScrollableArea.h ('k') | Source/core/rendering/RenderLayerStackingNode.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698