OLD | NEW |
---|---|
1 /* | 1 /* |
2 * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved. | 2 * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved. |
3 * | 3 * |
4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
5 * modification, are permitted provided that the following conditions | 5 * modification, are permitted provided that the following conditions |
6 * are met: | 6 * are met: |
7 * 1. Redistributions of source code must retain the above copyright | 7 * 1. Redistributions of source code must retain the above copyright |
8 * notice, this list of conditions and the following disclaimer. | 8 * notice, this list of conditions and the following disclaimer. |
9 * 2. Redistributions in binary form must reproduce the above copyright | 9 * 2. Redistributions in binary form must reproduce the above copyright |
10 * notice, this list of conditions and the following disclaimer in the | 10 * notice, this list of conditions and the following disclaimer in the |
(...skipping 13 matching lines...) Expand all Loading... | |
24 */ | 24 */ |
25 | 25 |
26 #include "config.h" | 26 #include "config.h" |
27 #include "platform/scroll/ScrollView.h" | 27 #include "platform/scroll/ScrollView.h" |
28 | 28 |
29 #include "platform/graphics/GraphicsContextStateSaver.h" | 29 #include "platform/graphics/GraphicsContextStateSaver.h" |
30 #include "platform/graphics/GraphicsLayer.h" | 30 #include "platform/graphics/GraphicsLayer.h" |
31 #include "platform/HostWindow.h" | 31 #include "platform/HostWindow.h" |
32 #include "platform/scroll/ScrollbarTheme.h" | 32 #include "platform/scroll/ScrollbarTheme.h" |
33 #include "wtf/StdLibExtras.h" | 33 #include "wtf/StdLibExtras.h" |
34 #include "wtf/TemporaryChange.h" | |
34 | 35 |
35 using namespace std; | 36 using namespace std; |
36 | 37 |
37 namespace WebCore { | 38 namespace WebCore { |
38 | 39 |
39 ScrollView::ScrollView() | 40 ScrollView::ScrollView() |
40 : m_horizontalScrollbarMode(ScrollbarAuto) | 41 : m_horizontalScrollbarMode(ScrollbarAuto) |
41 , m_verticalScrollbarMode(ScrollbarAuto) | 42 , m_verticalScrollbarMode(ScrollbarAuto) |
42 , m_horizontalScrollbarLock(false) | 43 , m_horizontalScrollbarLock(false) |
43 , m_verticalScrollbarLock(false) | 44 , m_verticalScrollbarLock(false) |
44 , m_scrollbarsAvoidingResizer(0) | 45 , m_scrollbarsAvoidingResizer(0) |
45 , m_scrollbarsSuppressed(false) | 46 , m_scrollbarsSuppressed(false) |
46 , m_inUpdateScrollbars(false) | 47 , m_inUpdateScrollbars(false) |
47 , m_updateScrollbarsPass(0) | |
48 , m_drawPanScrollIcon(false) | 48 , m_drawPanScrollIcon(false) |
49 , m_paintsEntireContents(false) | 49 , m_paintsEntireContents(false) |
50 , m_clipsRepaints(true) | 50 , m_clipsRepaints(true) |
51 { | 51 { |
52 } | 52 } |
53 | 53 |
54 ScrollView::~ScrollView() | 54 ScrollView::~ScrollView() |
55 { | 55 { |
56 } | 56 } |
57 | 57 |
(...skipping 259 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
317 stretch.setHeight(currentScrollPosition.y() - maxScrollPosition.y()); | 317 stretch.setHeight(currentScrollPosition.y() - maxScrollPosition.y()); |
318 | 318 |
319 return stretch; | 319 return stretch; |
320 } | 320 } |
321 | 321 |
322 void ScrollView::windowResizerRectChanged() | 322 void ScrollView::windowResizerRectChanged() |
323 { | 323 { |
324 updateScrollbars(scrollOffset()); | 324 updateScrollbars(scrollOffset()); |
325 } | 325 } |
326 | 326 |
327 static const unsigned cMaxUpdateScrollbarsPass = 2; | 327 static bool useOverlayScrollbars() |
328 { | |
329 // FIXME: Need to consider CSS custom scrollbars. | |
Julien - ping for review
2014/06/05 21:10:03
Custom CSS scrollbars are not-overlay scrollbars (
trchen
2014/06/05 23:55:27
How about this:
// FIXME: Need to detect the prese
| |
330 return ScrollbarTheme::theme()->usesOverlayScrollbars(); | |
331 } | |
328 | 332 |
329 void ScrollView::updateScrollbars(const IntSize& desiredOffset) | 333 void ScrollView::computeScrollbarExistence(bool& newHasHorizontalScrollbar, bool & newHasVerticalScrollbar, ComputeScrollbarExistenceOption option) const |
330 { | 334 { |
331 if (m_inUpdateScrollbars) | |
332 return; | |
333 | |
334 // If we came in here with the view already needing a layout, then go ahead and do that | |
335 // first. (This will be the common case, e.g., when the page changes due to window resizing for example). | |
336 // This layout will not re-enter updateScrollbars and does not count towards our max layout pass total. | |
337 if (!m_scrollbarsSuppressed) { | |
338 m_inUpdateScrollbars = true; | |
339 scrollbarExistenceDidChange(); | |
340 m_inUpdateScrollbars = false; | |
341 } | |
342 | |
343 IntRect oldScrollCornerRect = scrollCornerRect(); | |
344 | |
345 bool hasHorizontalScrollbar = m_horizontalScrollbar; | 335 bool hasHorizontalScrollbar = m_horizontalScrollbar; |
346 bool hasVerticalScrollbar = m_verticalScrollbar; | 336 bool hasVerticalScrollbar = m_verticalScrollbar; |
347 | 337 |
348 bool newHasHorizontalScrollbar = hasHorizontalScrollbar; | 338 newHasHorizontalScrollbar = hasHorizontalScrollbar; |
349 bool newHasVerticalScrollbar = hasVerticalScrollbar; | 339 newHasVerticalScrollbar = hasVerticalScrollbar; |
350 | 340 |
351 ScrollbarMode hScroll = m_horizontalScrollbarMode; | 341 ScrollbarMode hScroll = m_horizontalScrollbarMode; |
352 ScrollbarMode vScroll = m_verticalScrollbarMode; | 342 ScrollbarMode vScroll = m_verticalScrollbarMode; |
353 | 343 |
354 if (hScroll != ScrollbarAuto) | 344 if (hScroll != ScrollbarAuto) |
355 newHasHorizontalScrollbar = (hScroll == ScrollbarAlwaysOn); | 345 newHasHorizontalScrollbar = (hScroll == ScrollbarAlwaysOn); |
356 if (vScroll != ScrollbarAuto) | 346 if (vScroll != ScrollbarAuto) |
357 newHasVerticalScrollbar = (vScroll == ScrollbarAlwaysOn); | 347 newHasVerticalScrollbar = (vScroll == ScrollbarAlwaysOn); |
358 | 348 |
359 if (m_scrollbarsSuppressed || (hScroll != ScrollbarAuto && vScroll != Scroll barAuto)) { | 349 if (m_scrollbarsSuppressed || (hScroll != ScrollbarAuto && vScroll != Scroll barAuto)) |
360 if (hasHorizontalScrollbar != newHasHorizontalScrollbar) | 350 return; |
361 setHasHorizontalScrollbar(newHasHorizontalScrollbar); | |
362 if (hasVerticalScrollbar != newHasVerticalScrollbar) | |
363 setHasVerticalScrollbar(newHasVerticalScrollbar); | |
364 } else { | |
365 bool scrollbarExistenceChanged = false; | |
366 | 351 |
367 IntSize docSize = contentsSize(); | 352 IntSize docSize = contentsSize(); |
368 IntSize fullVisibleSize = visibleContentRect(IncludeScrollbars).size(); | |
369 | 353 |
370 bool scrollbarsAreOverlay = ScrollbarTheme::theme()->usesOverlayScrollba rs(); | 354 if (hScroll == ScrollbarAuto) |
355 newHasHorizontalScrollbar = docSize.width() > visibleWidth(); | |
356 if (vScroll == ScrollbarAuto) | |
357 newHasVerticalScrollbar = docSize.height() > visibleHeight(); | |
371 | 358 |
372 if (hScroll == ScrollbarAuto) { | 359 if (useOverlayScrollbars()) |
373 newHasHorizontalScrollbar = docSize.width() > visibleWidth(); | 360 return; |
374 if (!scrollbarsAreOverlay && newHasHorizontalScrollbar && !m_updateS crollbarsPass && docSize.width() <= fullVisibleSize.width() && docSize.height() <= fullVisibleSize.height()) | |
375 newHasHorizontalScrollbar = false; | |
376 } | |
377 if (vScroll == ScrollbarAuto) { | |
378 newHasVerticalScrollbar = docSize.height() > visibleHeight(); | |
379 if (!scrollbarsAreOverlay && newHasVerticalScrollbar && !m_updateScr ollbarsPass && docSize.width() <= fullVisibleSize.width() && docSize.height() <= fullVisibleSize.height()) | |
380 newHasVerticalScrollbar = false; | |
381 } | |
382 | 361 |
383 if (!scrollbarsAreOverlay) { | 362 IntSize fullVisibleSize = visibleContentRect(IncludeScrollbars).size(); |
384 // If we ever turn one scrollbar off, always turn the other one off too. Never ever | |
385 // try to both gain/lose a scrollbar in the same pass. | |
386 if (!newHasHorizontalScrollbar && hasHorizontalScrollbar && vScroll != ScrollbarAlwaysOn) | |
387 newHasVerticalScrollbar = false; | |
388 if (!newHasVerticalScrollbar && hasVerticalScrollbar && hScroll != S crollbarAlwaysOn) | |
389 newHasHorizontalScrollbar = false; | |
390 } | |
391 | 363 |
392 if (hasHorizontalScrollbar != newHasHorizontalScrollbar) { | 364 bool attemptToRemoveScrollbars = (option == AttemptToRemoveScrollbarsInCriti calCase |
393 scrollbarExistenceChanged = true; | 365 && docSize.width() <= fullVisibleSize.width() && docSize.height() <= ful lVisibleSize.height()); |
394 if (scrollOrigin().y() && !newHasHorizontalScrollbar && !scrollbarsA reOverlay) | 366 if (attemptToRemoveScrollbars) { |
395 ScrollableArea::setScrollOrigin(IntPoint(scrollOrigin().x(), scr ollOrigin().y() - m_horizontalScrollbar->height())); | 367 if (hScroll == ScrollbarAuto) |
Julien - ping for review
2014/06/05 21:10:03
Don't we need to keep this call to make sure the s
trchen
2014/06/05 23:55:27
This line is actually bogus. There is no way for S
| |
396 if (hasHorizontalScrollbar) | 368 newHasHorizontalScrollbar = false; |
397 m_horizontalScrollbar->invalidate(); | 369 if (vScroll == ScrollbarAuto) |
398 setHasHorizontalScrollbar(newHasHorizontalScrollbar); | 370 newHasVerticalScrollbar = false; |
399 } | |
400 | |
401 if (hasVerticalScrollbar != newHasVerticalScrollbar) { | |
402 scrollbarExistenceChanged = true; | |
403 if (scrollOrigin().x() && !newHasVerticalScrollbar && !scrollbarsAre Overlay) | |
404 ScrollableArea::setScrollOrigin(IntPoint(scrollOrigin().x() - m_ verticalScrollbar->width(), scrollOrigin().y())); | |
405 if (hasVerticalScrollbar) | |
406 m_verticalScrollbar->invalidate(); | |
407 setHasVerticalScrollbar(newHasVerticalScrollbar); | |
408 } | |
409 | |
410 if (scrollbarExistenceChanged) { | |
411 if (scrollbarsAreOverlay) { | |
412 // Synchronize status of scrollbar layers if necessary. | |
413 m_inUpdateScrollbars = true; | |
414 scrollbarExistenceDidChange(); | |
415 m_inUpdateScrollbars = false; | |
416 } else if (m_updateScrollbarsPass < cMaxUpdateScrollbarsPass) { | |
417 m_updateScrollbarsPass++; | |
418 contentsResized(); | |
419 scrollbarExistenceDidChange(); | |
420 IntSize newDocSize = contentsSize(); | |
421 if (newDocSize == docSize) { | |
422 // The layout with the new scroll state had no impact on | |
423 // the document's overall size, so updateScrollbars didn't g et called. | |
424 // Recur manually. | |
425 updateScrollbars(desiredOffset); | |
426 } | |
427 m_updateScrollbarsPass--; | |
428 } | |
429 } | |
430 } | 371 } |
431 | 372 |
432 // Set up the range, but only do this if we're not in a nested call (to avoi d | 373 // If we ever turn one scrollbar off, always turn the other one off too. |
433 // doing it multiple times). | 374 // Never ever try to both gain/lose a scrollbar in the same pass. |
434 if (m_updateScrollbarsPass) | 375 if (!newHasHorizontalScrollbar && hasHorizontalScrollbar && vScroll != Scrol lbarAlwaysOn) |
435 return; | 376 newHasVerticalScrollbar = false; |
377 if (!newHasVerticalScrollbar && hasVerticalScrollbar && hScroll != Scrollbar AlwaysOn) | |
378 newHasHorizontalScrollbar = false; | |
379 } | |
436 | 380 |
437 m_inUpdateScrollbars = true; | 381 void ScrollView::updateScrollbarGeometry() |
438 | 382 { |
439 if (m_horizontalScrollbar) { | 383 if (m_horizontalScrollbar) { |
440 int clientWidth = visibleWidth(); | 384 int clientWidth = visibleWidth(); |
441 IntRect oldRect(m_horizontalScrollbar->frameRect()); | 385 IntRect oldRect(m_horizontalScrollbar->frameRect()); |
442 IntRect hBarRect((shouldPlaceVerticalScrollbarOnLeft() && m_verticalScro llbar) ? m_verticalScrollbar->width() : 0, | 386 IntRect hBarRect((shouldPlaceVerticalScrollbarOnLeft() && m_verticalScro llbar) ? m_verticalScrollbar->width() : 0, |
443 height() - m_horizontalScrollbar->height(), | 387 height() - m_horizontalScrollbar->height(), |
444 width() - (m_verticalScrollbar ? m_verticalScrollbar->wi dth() : 0), | 388 width() - (m_verticalScrollbar ? m_verticalScrollbar->wi dth() : 0), |
445 m_horizontalScrollbar->height()); | 389 m_horizontalScrollbar->height()); |
446 m_horizontalScrollbar->setFrameRect(hBarRect); | 390 m_horizontalScrollbar->setFrameRect(hBarRect); |
447 if (!m_scrollbarsSuppressed && oldRect != m_horizontalScrollbar->frameRe ct()) | 391 if (!m_scrollbarsSuppressed && oldRect != m_horizontalScrollbar->frameRe ct()) |
448 m_horizontalScrollbar->invalidate(); | 392 m_horizontalScrollbar->invalidate(); |
(...skipping 17 matching lines...) Expand all Loading... | |
466 if (!m_scrollbarsSuppressed && oldRect != m_verticalScrollbar->frameRect ()) | 410 if (!m_scrollbarsSuppressed && oldRect != m_verticalScrollbar->frameRect ()) |
467 m_verticalScrollbar->invalidate(); | 411 m_verticalScrollbar->invalidate(); |
468 | 412 |
469 if (m_scrollbarsSuppressed) | 413 if (m_scrollbarsSuppressed) |
470 m_verticalScrollbar->setSuppressInvalidation(true); | 414 m_verticalScrollbar->setSuppressInvalidation(true); |
471 m_verticalScrollbar->setEnabled(contentsHeight() > clientHeight); | 415 m_verticalScrollbar->setEnabled(contentsHeight() > clientHeight); |
472 m_verticalScrollbar->setProportion(clientHeight, contentsHeight()); | 416 m_verticalScrollbar->setProportion(clientHeight, contentsHeight()); |
473 if (m_scrollbarsSuppressed) | 417 if (m_scrollbarsSuppressed) |
474 m_verticalScrollbar->setSuppressInvalidation(false); | 418 m_verticalScrollbar->setSuppressInvalidation(false); |
475 } | 419 } |
420 } | |
476 | 421 |
477 if (hasHorizontalScrollbar != newHasHorizontalScrollbar || hasVerticalScroll bar != newHasVerticalScrollbar) { | 422 bool ScrollView::adjustScrollbarExistence(ComputeScrollbarExistenceOption option ) |
423 { | |
424 ASSERT(m_inUpdateScrollbars); | |
425 | |
426 // If we came in here with the view already needing a layout, then go ahead and do that | |
427 // first. (This will be the common case, e.g., when the page changes due to window resizing for example). | |
428 // This layout will not re-enter updateScrollbars and does not count towards our max layout pass total. | |
429 if (!m_scrollbarsSuppressed) | |
430 scrollbarExistenceDidChange(); | |
431 | |
432 bool hasHorizontalScrollbar = m_horizontalScrollbar; | |
433 bool hasVerticalScrollbar = m_verticalScrollbar; | |
434 | |
435 bool newHasHorizontalScrollbar = false; | |
436 bool newHasVerticalScrollbar = false; | |
437 computeScrollbarExistence(newHasHorizontalScrollbar, newHasVerticalScrollbar , option); | |
438 | |
439 bool scrollbarExistenceChanged = hasHorizontalScrollbar != newHasHorizontalS crollbar || hasVerticalScrollbar != newHasVerticalScrollbar; | |
440 if (!scrollbarExistenceChanged) | |
441 return false; | |
442 | |
443 setHasHorizontalScrollbar(newHasHorizontalScrollbar); | |
444 setHasVerticalScrollbar(newHasVerticalScrollbar); | |
445 | |
446 if (m_scrollbarsSuppressed) | |
447 return true; | |
448 | |
449 if (!useOverlayScrollbars()) | |
450 contentsResized(); | |
451 scrollbarExistenceDidChange(); | |
452 return true; | |
453 } | |
454 | |
455 void ScrollView::updateScrollbars(const IntSize& desiredOffset) | |
456 { | |
457 if (m_inUpdateScrollbars) | |
458 return; | |
459 TemporaryChange<bool> inUpdateScrollbarsChange(m_inUpdateScrollbars, true); | |
460 | |
461 IntSize oldVisibleSize = visibleSize(); | |
462 | |
463 bool scrollbarExistenceChanged = false; | |
464 int maxUpdateScrollbarsPass = useOverlayScrollbars() || m_scrollbarsSuppress ed ? 1 : 3; | |
465 for (int updateScrollbarsPass = 0; updateScrollbarsPass < maxUpdateScrollbar sPass; updateScrollbarsPass++) { | |
466 if (!adjustScrollbarExistence(updateScrollbarsPass ? Lazy : AttemptToRem oveScrollbarsInCriticalCase)) | |
Julien - ping for review
2014/06/05 21:10:03
It's interesting that you call the passes Lazy vs
trchen
2014/06/05 23:55:27
Interesting! Our point of view is very different o
| |
467 break; | |
468 scrollbarExistenceChanged = true; | |
469 } | |
470 | |
471 updateScrollbarGeometry(); | |
472 | |
473 if (scrollbarExistenceChanged) { | |
478 // FIXME: Is frameRectsChanged really necessary here? Have any frame rec ts changed? | 474 // FIXME: Is frameRectsChanged really necessary here? Have any frame rec ts changed? |
479 frameRectsChanged(); | 475 frameRectsChanged(); |
480 positionScrollbarLayers(); | 476 positionScrollbarLayers(); |
481 updateScrollCorner(); | 477 updateScrollCorner(); |
482 if (!m_horizontalScrollbar && !m_verticalScrollbar) | |
483 invalidateScrollCornerRect(oldScrollCornerRect); | |
Julien - ping for review
2014/06/05 21:10:03
Don't we need to invalidate the scroll-corner if w
trchen
2014/06/05 23:55:27
Yes. I also removed the invalidation when we lose
| |
484 } | 478 } |
485 | 479 |
480 // FIXME: We don't need to do this if we are composited. | |
481 IntSize newVisibleSize = visibleSize(); | |
482 if (newVisibleSize.width() > oldVisibleSize.width()) { | |
483 if (shouldPlaceVerticalScrollbarOnLeft()) | |
484 invalidateRect(IntRect(0, 0, newVisibleSize.width() - oldVisibleSize .width(), newVisibleSize.height())); | |
485 else | |
486 invalidateRect(IntRect(oldVisibleSize.width(), 0, newVisibleSize.wid th() - oldVisibleSize.width(), newVisibleSize.height())); | |
487 } | |
488 if (newVisibleSize.height() > oldVisibleSize.height()) | |
489 invalidateRect(IntRect(0, oldVisibleSize.height(), newVisibleSize.width( ), newVisibleSize.height() - oldVisibleSize.height())); | |
490 | |
486 IntPoint adjustedScrollPosition = IntPoint(desiredOffset); | 491 IntPoint adjustedScrollPosition = IntPoint(desiredOffset); |
487 if (!isRubberBandInProgress()) | 492 if (!isRubberBandInProgress()) |
488 adjustedScrollPosition = adjustScrollPositionWithinRange(adjustedScrollP osition); | 493 adjustedScrollPosition = adjustScrollPositionWithinRange(adjustedScrollP osition); |
489 | |
490 if (adjustedScrollPosition != scrollPosition() || scrollOriginChanged()) { | 494 if (adjustedScrollPosition != scrollPosition() || scrollOriginChanged()) { |
491 ScrollableArea::scrollToOffsetWithoutAnimation(adjustedScrollPosition); | 495 ScrollableArea::scrollToOffsetWithoutAnimation(adjustedScrollPosition); |
492 resetScrollOriginChanged(); | 496 resetScrollOriginChanged(); |
493 } | 497 } |
494 | |
495 // Make sure the scrollbar offsets are up to date. | |
496 if (m_horizontalScrollbar) | |
497 m_horizontalScrollbar->offsetDidChange(); | |
Julien - ping for review
2014/06/05 21:10:03
Won't that break custom scrollbars as you don't se
trchen
2014/06/05 23:55:27
Ah I may have made a mistake here. I was thinking
| |
498 if (m_verticalScrollbar) | |
499 m_verticalScrollbar->offsetDidChange(); | |
500 | |
501 m_inUpdateScrollbars = false; | |
502 } | 498 } |
503 | 499 |
504 const int panIconSizeLength = 16; | 500 const int panIconSizeLength = 16; |
505 | 501 |
506 IntRect ScrollView::rectToCopyOnScroll() const | 502 IntRect ScrollView::rectToCopyOnScroll() const |
507 { | 503 { |
508 IntRect scrollViewRect = convertToRootView(IntRect((shouldPlaceVerticalScrol lbarOnLeft() && verticalScrollbar()) ? verticalScrollbar()->width() : 0, 0, visi bleWidth(), visibleHeight())); | 504 IntRect scrollViewRect = convertToRootView(IntRect((shouldPlaceVerticalScrol lbarOnLeft() && verticalScrollbar()) ? verticalScrollbar()->width() : 0, 0, visi bleWidth(), visibleHeight())); |
509 if (hasOverlayScrollbars()) { | 505 if (hasOverlayScrollbars()) { |
510 int verticalScrollbarWidth = (verticalScrollbar() && !hasLayerForVertica lScrollbar()) ? verticalScrollbar()->width() : 0; | 506 int verticalScrollbarWidth = (verticalScrollbar() && !hasLayerForVertica lScrollbar()) ? verticalScrollbar()->width() : 0; |
511 int horizontalScrollbarHeight = (horizontalScrollbar() && !hasLayerForHo rizontalScrollbar()) ? horizontalScrollbar()->height() : 0; | 507 int horizontalScrollbarHeight = (horizontalScrollbar() && !hasLayerForHo rizontalScrollbar()) ? horizontalScrollbar()->height() : 0; |
(...skipping 602 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1114 return; | 1110 return; |
1115 | 1111 |
1116 ScrollableArea::setScrollOrigin(origin); | 1112 ScrollableArea::setScrollOrigin(origin); |
1117 | 1113 |
1118 // Update if the scroll origin changes, since our position will be different if the content size did not change. | 1114 // Update if the scroll origin changes, since our position will be different if the content size did not change. |
1119 if (updatePositionAtAll && updatePositionSynchronously) | 1115 if (updatePositionAtAll && updatePositionSynchronously) |
1120 updateScrollbars(scrollOffset()); | 1116 updateScrollbars(scrollOffset()); |
1121 } | 1117 } |
1122 | 1118 |
1123 } // namespace WebCore | 1119 } // namespace WebCore |
OLD | NEW |