void AccessibilityObject::scrollToGlobalPoint(const IntPoint& globalPoint) const { // Search up the parent chain and create a vector of all scrollable parent objects // and ending with this object itself. Vector<const AccessibilityObject*> objects; AccessibilityObject* parentObject; for (parentObject = this->parentObject(); parentObject; parentObject = parentObject->parentObject()) { if (parentObject->getScrollableAreaIfScrollable()) objects.prepend(parentObject); } objects.append(this); // Start with the outermost scrollable (the main window) and try to scroll the // next innermost object to the given point. int offsetX = 0, offsetY = 0; IntPoint point = globalPoint; size_t levels = objects.size() - 1; for (size_t i = 0; i < levels; i++) { const AccessibilityObject* outer = objects[i]; const AccessibilityObject* inner = objects[i + 1]; ScrollableArea* scrollableArea = outer->getScrollableAreaIfScrollable(); LayoutRect innerRect = inner->isAccessibilityScrollView() ? inner->parentObject()->elementRect() : inner->elementRect(); LayoutRect objectRect = innerRect; IntPoint scrollPosition = scrollableArea->scrollPosition(); // Convert the object rect into local coordinates. objectRect.move(offsetX, offsetY); if (!outer->isAccessibilityScrollView()) objectRect.move(scrollPosition.x(), scrollPosition.y()); int desiredX = computeBestScrollOffset( 0, objectRect.x(), objectRect.maxX(), objectRect.x(), objectRect.maxX(), point.x(), point.x()); int desiredY = computeBestScrollOffset( 0, objectRect.y(), objectRect.maxY(), objectRect.y(), objectRect.maxY(), point.y(), point.y()); outer->scrollTo(IntPoint(desiredX, desiredY)); if (outer->isAccessibilityScrollView() && !inner->isAccessibilityScrollView()) { // If outer object we just scrolled is a scroll view (main window or iframe) but the // inner object is not, keep track of the coordinate transformation to apply to // future nested calculations. scrollPosition = scrollableArea->scrollPosition(); offsetX -= (scrollPosition.x() + point.x()); offsetY -= (scrollPosition.y() + point.y()); point.move(scrollPosition.x() - innerRect.x(), scrollPosition.y() - innerRect.y()); } else if (inner->isAccessibilityScrollView()) { // Otherwise, if the inner object is a scroll view, reset the coordinate transformation. offsetX = 0; offsetY = 0; } } }
IntPoint AXObject::scrollOffset() const { ScrollableArea* area = getScrollableAreaIfScrollable(); if (!area) return IntPoint(); return IntPoint(area->scrollPosition().x(), area->scrollPosition().y()); }
void AccessibilityObject::scrollToMakeVisibleWithSubFocus(const IntRect& subfocus) const { // Search up the parent chain until we find the first one that's scrollable. AccessibilityObject* scrollParent = parentObject(); ScrollableArea* scrollableArea; for (scrollableArea = 0; scrollParent && !(scrollableArea = scrollParent->getScrollableAreaIfScrollable()); scrollParent = scrollParent->parentObject()) { } if (!scrollableArea) return; LayoutRect objectRect = elementRect(); IntPoint scrollPosition = scrollableArea->scrollPosition(); IntRect scrollVisibleRect = scrollableArea->visibleContentRect(); int desiredX = computeBestScrollOffset( scrollPosition.x(), objectRect.x() + subfocus.x(), objectRect.x() + subfocus.maxX(), objectRect.x(), objectRect.maxX(), 0, scrollVisibleRect.width()); int desiredY = computeBestScrollOffset( scrollPosition.y(), objectRect.y() + subfocus.y(), objectRect.y() + subfocus.maxY(), objectRect.y(), objectRect.maxY(), 0, scrollVisibleRect.height()); scrollParent->scrollTo(IntPoint(desiredX, desiredY)); // Recursively make sure the scroll parent itself is visible. if (scrollParent->parentObject()) scrollParent->scrollToMakeVisible(); }
InRegionScrollableArea::InRegionScrollableArea(WebPagePrivate* webPage, RenderLayer* layer) : m_webPage(webPage) , m_layer(layer) { ASSERT(webPage); ASSERT(layer); m_isNull = false; // FIXME: Add an ASSERT here as the 'layer' must be scrollable. RenderObject* layerRenderer = layer->renderer(); ASSERT(layerRenderer); if (layerRenderer->isRenderView()) { // #document case FrameView* view = toRenderView(layerRenderer)->frameView(); ASSERT(view); Frame* frame = view->frame(); ASSERT_UNUSED(frame, frame); m_scrollPosition = m_webPage->mapToTransformed(view->scrollPosition()); m_contentsSize = m_webPage->mapToTransformed(view->contentsSize()); m_viewportSize = m_webPage->mapToTransformed(view->visibleContentRect(false /*includeScrollbars*/)).size(); m_visibleWindowRect = m_webPage->mapToTransformed(m_webPage->getRecursiveVisibleWindowRect(view)); IntRect transformedWindowRect = IntRect(IntPoint::zero(), m_webPage->transformedViewportSize()); m_visibleWindowRect.intersect(transformedWindowRect); m_scrollsHorizontally = view->contentsWidth() > view->visibleWidth(); m_scrollsVertically = view->contentsHeight() > view->visibleHeight(); m_overscrollLimitFactor = 0.0; // FIXME eventually support overscroll } else { // RenderBox-based elements case (scrollable boxes (div's, p's, textarea's, etc)). RenderBox* box = m_layer->renderBox(); ASSERT(box); ASSERT(box->canBeScrolledAndHasScrollableArea()); ScrollableArea* scrollableArea = static_cast<ScrollableArea*>(m_layer); m_scrollPosition = m_webPage->mapToTransformed(scrollableArea->scrollPosition()); m_contentsSize = m_webPage->mapToTransformed(scrollableArea->contentsSize()); m_viewportSize = m_webPage->mapToTransformed(scrollableArea->visibleContentRect(false /*includeScrollbars*/)).size(); m_visibleWindowRect = m_layer->renderer()->absoluteClippedOverflowRect(); m_visibleWindowRect = m_layer->renderer()->frame()->view()->contentsToWindow(m_visibleWindowRect); IntRect visibleFrameWindowRect = m_webPage->getRecursiveVisibleWindowRect(m_layer->renderer()->frame()->view()); m_visibleWindowRect.intersect(visibleFrameWindowRect); m_visibleWindowRect = m_webPage->mapToTransformed(m_visibleWindowRect); IntRect transformedWindowRect = IntRect(IntPoint::zero(), m_webPage->transformedViewportSize()); m_visibleWindowRect.intersect(transformedWindowRect); m_scrollsHorizontally = box->scrollWidth() != box->clientWidth() && box->scrollsOverflowX(); m_scrollsVertically = box->scrollHeight() != box->clientHeight() && box->scrollsOverflowY(); m_overscrollLimitFactor = 0.0; // FIXME eventually support overscroll } }
void AXObject::scrollToMakeVisibleWithSubFocus(const IntRect& subfocus) const { // Search up the parent chain until we find the first one that's scrollable. AXObject* scrollParent = parentObject(); ScrollableArea* scrollableArea = 0; while (scrollParent) { scrollableArea = scrollParent->getScrollableAreaIfScrollable(); if (scrollableArea && !scrollParent->isAXScrollView()) break; scrollParent = scrollParent->parentObject(); } if (!scrollParent || !scrollableArea) return; IntRect objectRect = pixelSnappedIntRect(elementRect()); IntPoint scrollPosition = scrollableArea->scrollPosition(); IntRect scrollVisibleRect = scrollableArea->visibleContentRect(); // Convert the object rect into local coordinates. if (!scrollParent->isWebArea()) { objectRect.moveBy(scrollPosition); objectRect.moveBy(-pixelSnappedIntRect(scrollParent->elementRect()).location()); } int desiredX = computeBestScrollOffset( scrollPosition.x(), objectRect.x() + subfocus.x(), objectRect.x() + subfocus.maxX(), objectRect.x(), objectRect.maxX(), 0, scrollVisibleRect.width()); int desiredY = computeBestScrollOffset( scrollPosition.y(), objectRect.y() + subfocus.y(), objectRect.y() + subfocus.maxY(), objectRect.y(), objectRect.maxY(), 0, scrollVisibleRect.height()); scrollParent->setScrollOffset(IntPoint(desiredX, desiredY)); // Convert the subfocus into the coordinates of the scroll parent. IntRect newSubfocus = subfocus; IntRect newElementRect = pixelSnappedIntRect(elementRect()); IntRect scrollParentRect = pixelSnappedIntRect(scrollParent->elementRect()); newSubfocus.move(newElementRect.x(), newElementRect.y()); newSubfocus.move(-scrollParentRect.x(), -scrollParentRect.y()); // Recursively make sure the scroll parent itself is visible. if (scrollParent->parentObject()) scrollParent->scrollToMakeVisibleWithSubFocus(newSubfocus); }
InRegionScrollableArea::InRegionScrollableArea(WebPagePrivate* webPage, RenderLayer* layer) : m_webPage(webPage) , m_layer(layer) , m_document(0) , m_hasWindowVisibleRectCalculated(false) { ASSERT(webPage); ASSERT(layer); m_isNull = false; // Add a pointer to the enclosing document as the pointer to layer or node along the way may become invalid. if (m_layer->enclosingElement()) m_document = m_layer->enclosingElement()->document(); // FIXME: Add an ASSERT here as the 'layer' must be scrollable. RenderObject* layerRenderer = layer->renderer(); ASSERT(layerRenderer); if (layerRenderer->isRenderView()) { // #document case RenderView* renderView = toRenderView(layerRenderer); ASSERT(renderView); FrameView* view = toRenderView(layerRenderer)->frameView(); ASSERT(view); Frame* frame = view->frame(); ASSERT_UNUSED(frame, frame); const Platform::ViewportAccessor* viewportAccessor = m_webPage->m_webkitThreadViewportAccessor; m_scrollPosition = viewportAccessor->roundToPixelFromDocumentContents(WebCore::FloatPoint(view->scrollPosition())); m_contentsSize = viewportAccessor->roundToPixelFromDocumentContents(Platform::FloatRect(Platform::FloatPoint::zero(), WebCore::FloatSize(view->contentsSize()))).size(); m_viewportSize = viewportAccessor->roundToPixelFromDocumentContents(WebCore::FloatRect(view->visibleContentRect(ScrollableArea::ExcludeScrollbars))).size(); m_documentViewportRect = view->frameRect(); m_scrollsHorizontally = view->contentsWidth() > view->visibleWidth(); m_scrollsVertically = view->contentsHeight() > view->visibleHeight(); m_supportsCompositedScrolling = true; m_scrollTarget = InnerFrame; ASSERT(!m_cachedNonCompositedScrollableNode); m_camouflagedCompositedScrollableLayer = reinterpret_cast<unsigned>(renderView->compositor()->scrollLayer()->platformLayer()); m_cachedCompositedScrollableLayer = renderView->compositor()->scrollLayer()->platformLayer(); } else { // RenderBox-based elements case (scrollable boxes (div's, p's, textarea's, etc)). RenderBox* box = m_layer->renderBox(); ASSERT(box); ASSERT(InRegionScrollerPrivate::canScrollRenderBox(box)); const Platform::ViewportAccessor* viewportAccessor = m_webPage->m_webkitThreadViewportAccessor; ScrollableArea* scrollableArea = static_cast<ScrollableArea*>(m_layer); m_scrollPosition = viewportAccessor->roundToPixelFromDocumentContents(WebCore::FloatPoint(scrollableArea->scrollPosition())); m_contentsSize = viewportAccessor->roundToPixelFromDocumentContents(Platform::FloatRect(Platform::FloatPoint::zero(), WebCore::FloatSize(scrollableArea->contentsSize()))).size(); m_viewportSize = viewportAccessor->roundToPixelFromDocumentContents(WebCore::FloatRect(scrollableArea->visibleContentRect(ScrollableArea::ExcludeScrollbars))).size(); m_documentViewportRect = enclosingIntRect(box->absoluteClippedOverflowRect()); m_scrollsHorizontally = box->scrollWidth() != box->clientWidth(); m_scrollsVertically = box->scrollHeight() != box->clientHeight(); // Check the overflow if its not an input field because overflow can be set to hidden etc. by the content. if (!DOMSupport::isShadowHostTextInputElement(box->node())) { m_scrollsHorizontally = m_scrollsHorizontally && box->scrollsOverflowX(); m_scrollsVertically = m_scrollsVertically && box->scrollsOverflowY(); } m_scrollTarget = BlockElement; // Both caches below are self-exclusive. if (m_layer->usesCompositedScrolling()) { m_forceContentToBeHorizontallyScrollable = m_scrollsHorizontally; m_forceContentToBeVerticallyScrollable = m_scrollsVertically; // Force content to be scrollable even if it doesn't need to scroll in either direction. if (!m_scrollsHorizontally && !m_scrollsVertically) { if (box->scrollsOverflowY()) m_forceContentToBeVerticallyScrollable = true; else if (box->scrollsOverflowX()) // If it's already forced scrollable vertically, don't force it to scroll horizontally m_forceContentToBeHorizontallyScrollable = true; } m_supportsCompositedScrolling = true; ASSERT(m_layer->backing()->hasScrollingLayer()); m_camouflagedCompositedScrollableLayer = reinterpret_cast<unsigned>(m_layer->backing()->scrollingContentsLayer()->platformLayer()); m_cachedCompositedScrollableLayer = m_layer->backing()->scrollingContentsLayer()->platformLayer(); ASSERT(!m_cachedNonCompositedScrollableNode); } else { m_camouflagedCompositedScrollableLayer = reinterpret_cast<unsigned>(m_layer->enclosingElement()); m_cachedNonCompositedScrollableNode = m_layer->enclosingElement(); ASSERT(!m_cachedCompositedScrollableLayer); } } }
InRegionScrollableArea::InRegionScrollableArea(WebPagePrivate* webPage, RenderLayer* layer) : m_webPage(webPage) , m_layer(layer) , m_document(0) , m_hasWindowVisibleRectCalculated(false) { ASSERT(webPage); ASSERT(layer); m_isNull = false; // Add a pointer to the enclosing document as the pointer to layer or node along the way may become invalid. if (m_layer->enclosingElement()) m_document = m_layer->enclosingElement()->document(); // FIXME: Add an ASSERT here as the 'layer' must be scrollable. RenderObject* layerRenderer = layer->renderer(); ASSERT(layerRenderer); if (layerRenderer->isRenderView()) { // #document case RenderView* renderView = toRenderView(layerRenderer); ASSERT(renderView); FrameView* view = toRenderView(layerRenderer)->frameView(); ASSERT(view); Frame* frame = view->frame(); ASSERT_UNUSED(frame, frame); m_scrollPosition = m_webPage->mapToTransformed(view->scrollPosition()); m_contentsSize = m_webPage->mapToTransformed(view->contentsSize()); m_viewportSize = m_webPage->mapToTransformed(view->visibleContentRect(ScrollableArea::ExcludeScrollbars)).size(); m_documentViewportRect = view->frameRect(); m_scrollsHorizontally = view->contentsWidth() > view->visibleWidth(); m_scrollsVertically = view->contentsHeight() > view->visibleHeight(); m_supportsCompositedScrolling = true; m_scrollTarget = InnerFrame; ASSERT(!m_cachedNonCompositedScrollableNode); m_camouflagedCompositedScrollableLayer = reinterpret_cast<unsigned>(renderView->compositor()->scrollLayer()->platformLayer()); m_cachedCompositedScrollableLayer = renderView->compositor()->scrollLayer()->platformLayer(); } else { // RenderBox-based elements case (scrollable boxes (div's, p's, textarea's, etc)). RenderBox* box = m_layer->renderBox(); ASSERT(box); ASSERT(InRegionScrollerPrivate::canScrollRenderBox(box)); ScrollableArea* scrollableArea = static_cast<ScrollableArea*>(m_layer); m_scrollPosition = m_webPage->mapToTransformed(scrollableArea->scrollPosition()); m_contentsSize = m_webPage->mapToTransformed(scrollableArea->contentsSize()); m_viewportSize = m_webPage->mapToTransformed(scrollableArea->visibleContentRect(ScrollableArea::ExcludeScrollbars)).size(); m_documentViewportRect = enclosingIntRect(box->absoluteClippedOverflowRect()); m_scrollsHorizontally = box->scrollWidth() != box->clientWidth(); m_scrollsVertically = box->scrollHeight() != box->clientHeight(); // Check the overflow if its not an input field because overflow can be set to hidden etc. by the content. if (!box->node() || !box->node()->rendererIsEditable()) { m_scrollsHorizontally = m_scrollsHorizontally && box->scrollsOverflowX(); m_scrollsVertically = m_scrollsVertically && box->scrollsOverflowY(); } m_scrollTarget = BlockElement; // Both caches below are self-exclusive. if (m_layer->usesCompositedScrolling()) { m_forceContentToBeVerticallyScrollable = true; m_supportsCompositedScrolling = true; ASSERT(m_layer->backing()->hasScrollingLayer()); m_camouflagedCompositedScrollableLayer = reinterpret_cast<unsigned>(m_layer->backing()->scrollingContentsLayer()->platformLayer()); m_cachedCompositedScrollableLayer = m_layer->backing()->scrollingContentsLayer()->platformLayer(); ASSERT(!m_cachedNonCompositedScrollableNode); } else { m_camouflagedCompositedScrollableLayer = reinterpret_cast<unsigned>(m_layer->enclosingElement()); m_cachedNonCompositedScrollableNode = m_layer->enclosingElement(); ASSERT(!m_cachedCompositedScrollableLayer); } } }