| /* |
| * Copyright (C) 2023 Apple Inc. All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * |
| * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY |
| * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
| * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR |
| * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
| * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
| * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
| * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY |
| * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| #include "config.h" |
| #include "FrameView.h" |
| |
| #include "Chrome.h" |
| #include "ChromeClient.h" |
| #include "ContainerNodeInlines.h" |
| #include "FocusController.h" |
| #include "Frame.h" |
| #include "HTMLFrameOwnerElement.h" |
| #include "Page.h" |
| #include "RenderElement.h" |
| #include "RenderLayer.h" |
| #include "RenderLayerScrollableArea.h" |
| #include "RenderObjectInlines.h" |
| #include "RenderWidget.h" |
| #include <wtf/TZoneMallocInlines.h> |
| |
| namespace WebCore { |
| |
| WTF_MAKE_TZONE_ALLOCATED_IMPL(FrameView); |
| |
| int FrameView::headerHeight() const |
| { |
| Ref frame = this->frame(); |
| if (!frame->isMainFrame()) |
| return 0; |
| Page* page = frame->page(); |
| return page ? page->headerHeight() : 0; |
| } |
| |
| int FrameView::footerHeight() const |
| { |
| Ref frame = this->frame(); |
| if (!frame->isMainFrame()) |
| return 0; |
| Page* page = frame->page(); |
| return page ? page->footerHeight() : 0; |
| } |
| |
| FloatBoxExtent FrameView::obscuredContentInsets(InsetType type) const |
| { |
| if (platformWidget() && type == InsetType::WebCoreOrPlatformInset) |
| return platformContentInsets(); |
| |
| Ref frame = this->frame(); |
| if (!frame->isMainFrame()) |
| return { }; |
| |
| if (RefPtr page = frame->page()) |
| return page->obscuredContentInsets(); |
| |
| return { }; |
| } |
| |
| float FrameView::visibleContentScaleFactor() const |
| { |
| Ref frame = this->frame(); |
| if (!frame->isMainFrame()) |
| return 1; |
| |
| Page* page = frame->page(); |
| // FIXME: This !delegatesScaling() is confusing, and the opposite behavior to Frame::frameScaleFactor(). |
| // This function should probably be renamed to delegatedPageScaleFactor(). |
| if (!page || !page->delegatesScaling()) |
| return 1; |
| |
| return page->pageScaleFactor(); |
| } |
| |
| bool FrameView::isActive() const |
| { |
| Page* page = frame().page(); |
| return page && page->focusController().isActive(); |
| } |
| |
| ScrollableArea* FrameView::enclosingScrollableArea() const |
| { |
| Ref frame = this->frame(); |
| if (frame->isMainFrame()) |
| return nullptr; |
| |
| auto* ownerElement = frame->ownerElement(); |
| if (!ownerElement) |
| return nullptr; |
| |
| auto* ownerRenderer = ownerElement->renderer(); |
| if (!ownerRenderer) |
| return nullptr; |
| |
| auto* layer = ownerRenderer->enclosingLayer(); |
| if (!layer) |
| return nullptr; |
| |
| auto* enclosingScrollableLayer = layer->enclosingScrollableLayer(IncludeSelfOrNot::IncludeSelf, CrossFrameBoundaries::No); |
| if (!enclosingScrollableLayer) |
| return nullptr; |
| |
| return enclosingScrollableLayer->scrollableArea(); |
| } |
| |
| void FrameView::invalidateRect(const IntRect& rect) |
| { |
| Ref frame = this->frame(); |
| if (!parent()) { |
| if (auto* page = frame->page()) |
| page->chrome().invalidateContentsAndRootView(rect); |
| return; |
| } |
| |
| CheckedPtr renderer = frame->ownerRenderer(); |
| if (!renderer) |
| return; |
| |
| IntRect repaintRect = rect; |
| repaintRect.moveBy(roundedIntPoint(renderer->contentBoxLocation())); |
| renderer->repaintRectangle(repaintRect); |
| } |
| |
| bool FrameView::forceUpdateScrollbarsOnMainThreadForPerformanceTesting() const |
| { |
| Page* page = frame().page(); |
| return page && page->settings().scrollingPerformanceTestingEnabled(); |
| } |
| |
| IntRect FrameView::scrollableAreaBoundingBox(bool*) const |
| { |
| RefPtr ownerRenderer = frame().ownerRenderer(); |
| if (!ownerRenderer) |
| return frameRect(); |
| |
| return ownerRenderer->absoluteContentQuad().enclosingBoundingBox(); |
| } |
| |
| HostWindow* FrameView::hostWindow() const |
| { |
| auto* page = frame().page(); |
| return page ? &page->chrome() : nullptr; |
| } |
| |
| void FrameView::scrollbarStyleChanged(ScrollbarStyle newStyle, bool forceUpdate) |
| { |
| Ref frame = this->frame(); |
| if (!frame->isMainFrame()) |
| return; |
| |
| if (Page* page = frame->page()) |
| page->chrome().client().recommendedScrollbarStyleDidChange(newStyle); |
| |
| ScrollView::scrollbarStyleChanged(newStyle, forceUpdate); |
| } |
| |
| bool FrameView::scrollAnimatorEnabled() const |
| { |
| if (auto* page = frame().page()) |
| return page->settings().scrollAnimatorEnabled(); |
| |
| return false; |
| } |
| |
| #if ENABLE(FORM_CONTROL_REFRESH) |
| bool FrameView::formControlRefreshEnabled() const |
| { |
| if (RefPtr page = frame().page()) |
| return page->settings().formControlRefreshEnabled(); |
| |
| return false; |
| } |
| #endif |
| |
| // MARK: - |
| |
| IntPoint FrameView::convertFromRendererToContainingView(const RenderElement* renderer, IntPoint rendererPoint) const |
| { |
| auto point = roundedIntPoint(renderer->localToAbsolute(rendererPoint, UseTransforms)); |
| return contentsToView(point); |
| } |
| |
| FloatPoint FrameView::convertFromRendererToContainingView(const RenderElement* renderer, FloatPoint rendererPoint) const |
| { |
| auto point = renderer->localToAbsolute(rendererPoint, UseTransforms); |
| return contentsToView(point); |
| } |
| |
| IntRect FrameView::convertFromRendererToContainingView(const RenderElement* renderer, const IntRect& rendererRect) const |
| { |
| auto rect = snappedIntRect(enclosingLayoutRect(renderer->localToAbsoluteQuad(FloatRect(rendererRect)).boundingBox())); |
| return contentsToView(rect); |
| } |
| |
| FloatRect FrameView::convertFromRendererToContainingView(const RenderElement* renderer, const FloatRect& rendererRect) const |
| { |
| auto rect = renderer->localToAbsoluteQuad(FloatRect(rendererRect)).boundingBox(); |
| return contentsToView(rect); |
| } |
| |
| // MARK: - |
| |
| IntPoint FrameView::convertFromContainingViewToRenderer(const RenderElement* renderer, IntPoint viewPoint) const |
| { |
| auto point = viewPoint; |
| |
| // Convert from FrameView coords into page ("absolute") coordinates. |
| if (!delegatesScrollingToNativeView()) |
| point = viewToContents(point); |
| |
| return roundedIntPoint(renderer->absoluteToLocal(point, UseTransforms)); |
| } |
| |
| FloatPoint FrameView::convertFromContainingViewToRenderer(const RenderElement* renderer, FloatPoint viewPoint) const |
| { |
| auto point = viewPoint; |
| |
| // Convert from FrameView coords into page ("absolute") coordinates. |
| if (!delegatesScrollingToNativeView()) |
| point = viewToContents(point); |
| |
| return renderer->absoluteToLocal(point, UseTransforms); |
| } |
| |
| IntRect FrameView::convertFromContainingViewToRenderer(const RenderElement* renderer, const IntRect& viewRect) const |
| { |
| auto rect = viewToContents(viewRect); |
| |
| // FIXME: we don't have a way to map an absolute rect down to a local quad, so just |
| // move the rect for now. |
| rect.setLocation(roundedIntPoint(renderer->absoluteToLocal(rect.location(), UseTransforms))); |
| return rect; |
| } |
| |
| FloatRect FrameView::convertFromContainingViewToRenderer(const RenderElement* renderer, const FloatRect& viewRect) const |
| { |
| auto rect = viewToContents(viewRect); |
| |
| return renderer->absoluteToLocalQuad(rect).boundingBox(); |
| } |
| |
| // MARK: - |
| |
| IntPoint FrameView::convertToContainingView(IntPoint localPoint) const |
| { |
| if (auto* parentScrollView = parent()) { |
| if (auto* parentView = dynamicDowncast<FrameView>(*parentScrollView)) { |
| // Get our renderer in the parent view |
| RenderWidget* renderer = frame().ownerRenderer(); |
| if (!renderer) |
| return localPoint; |
| |
| auto point = localPoint; |
| point.moveBy(roundedIntPoint(renderer->contentBoxLocation())); |
| return parentView->convertFromRendererToContainingView(renderer, point); |
| } |
| return Widget::convertToContainingView(localPoint); |
| } |
| return localPoint; |
| } |
| |
| FloatPoint FrameView::convertToContainingView(FloatPoint localPoint) const |
| { |
| if (auto* parentScrollView = parent()) { |
| if (auto* parentView = dynamicDowncast<FrameView>(*parentScrollView)) { |
| // Get our renderer in the parent view |
| RenderWidget* renderer = frame().ownerRenderer(); |
| if (!renderer) |
| return localPoint; |
| |
| auto point = localPoint; |
| point.moveBy(renderer->contentBoxLocation()); |
| return parentView->convertFromRendererToContainingView(renderer, point); |
| } |
| return Widget::convertToContainingView(localPoint); |
| } |
| return localPoint; |
| } |
| |
| IntRect FrameView::convertToContainingView(const IntRect& localRect) const |
| { |
| if (auto* parentScrollView = parent()) { |
| if (auto* parentView = dynamicDowncast<FrameView>(*parentScrollView)) { |
| // Get our renderer in the parent view |
| RenderWidget* renderer = frame().ownerRenderer(); |
| if (!renderer) |
| return localRect; |
| |
| auto rect = localRect; |
| rect.moveBy(roundedIntPoint(renderer->contentBoxLocation())); |
| return parentView->convertFromRendererToContainingView(renderer, rect); |
| } |
| return Widget::convertToContainingView(localRect); |
| } |
| return localRect; |
| } |
| |
| FloatRect FrameView::convertToContainingView(const FloatRect& localRect) const |
| { |
| if (auto* parentScrollView = parent()) { |
| if (auto* parentView = dynamicDowncast<FrameView>(*parentScrollView)) { |
| // Get our renderer in the parent view |
| RenderWidget* renderer = frame().ownerRenderer(); |
| if (!renderer) |
| return localRect; |
| |
| auto rect = localRect; |
| rect.moveBy(renderer->contentBoxLocation()); |
| return parentView->convertFromRendererToContainingView(renderer, rect); |
| } |
| return Widget::convertToContainingView(localRect); |
| } |
| return localRect; |
| } |
| |
| // MARK: - |
| |
| IntPoint FrameView::convertFromContainingView(IntPoint parentPoint) const |
| { |
| if (auto* parentScrollView = parent()) { |
| if (auto* parentView = dynamicDowncast<FrameView>(*parentScrollView)) { |
| // Get our renderer in the parent view |
| RenderWidget* renderer = frame().ownerRenderer(); |
| if (!renderer) |
| return parentPoint; |
| |
| auto point = parentView->convertFromContainingViewToRenderer(renderer, parentPoint); |
| point.moveBy(-roundedIntPoint(renderer->contentBoxLocation())); |
| return point; |
| } |
| return Widget::convertFromContainingView(parentPoint); |
| } |
| return parentPoint; |
| } |
| |
| FloatPoint FrameView::convertFromContainingView(FloatPoint parentPoint) const |
| { |
| if (auto* parentScrollView = parent()) { |
| if (auto* parentView = dynamicDowncast<FrameView>(*parentScrollView)) { |
| // Get our renderer in the parent view |
| RenderWidget* renderer = frame().ownerRenderer(); |
| if (!renderer) |
| return parentPoint; |
| |
| auto point = parentView->convertFromContainingViewToRenderer(renderer, parentPoint); |
| point.moveBy(-renderer->contentBoxLocation()); |
| return point; |
| } |
| return Widget::convertFromContainingView(parentPoint); |
| } |
| return parentPoint; |
| } |
| |
| IntRect FrameView::convertFromContainingView(const IntRect& parentRect) const |
| { |
| if (auto* parentScrollView = parent()) { |
| if (auto* parentView = dynamicDowncast<FrameView>(*parentScrollView)) { |
| // Get our renderer in the parent view |
| RenderWidget* renderer = frame().ownerRenderer(); |
| if (!renderer) |
| return parentRect; |
| |
| auto rect = parentView->convertFromContainingViewToRenderer(renderer, parentRect); |
| rect.moveBy(-roundedIntPoint(renderer->contentBoxLocation())); |
| return rect; |
| } |
| return Widget::convertFromContainingView(parentRect); |
| } |
| return parentRect; |
| } |
| |
| FloatRect FrameView::convertFromContainingView(const FloatRect& parentRect) const |
| { |
| if (auto* parentScrollView = parent()) { |
| if (auto* parentView = dynamicDowncast<FrameView>(*parentScrollView)) { |
| // Get our renderer in the parent view |
| RenderWidget* renderer = frame().ownerRenderer(); |
| if (!renderer) |
| return parentRect; |
| |
| auto rect = parentView->convertFromContainingViewToRenderer(renderer, parentRect); |
| rect.moveBy(-renderer->contentBoxLocation()); |
| return rect; |
| } |
| return Widget::convertFromContainingView(parentRect); |
| } |
| return parentRect; |
| } |
| |
| } |