blob: bdef951ffa7b0739cfd65fdd5b6b6fd5a1c2ae0b [file] [log] [blame]
/*
* 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);
}
DoublePoint FrameView::convertFromContainingViewToRenderer(const RenderElement* renderer, DoublePoint viewPoint) const
{
// Convert from FrameView coords into page ("absolute") coordinates.
if (!delegatesScrollingToNativeView())
viewPoint = viewToContents(viewPoint);
return renderer->absoluteToLocal(viewPoint, 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;
}
DoublePoint FrameView::convertFromContainingView(DoublePoint parentPoint) const
{
if (RefPtr parentScrollView = parent()) {
if (RefPtr parentView = dynamicDowncast<FrameView>(*parentScrollView)) {
// Get our renderer in the parent view
RefPtr renderer = frame().ownerRenderer();
if (!renderer)
return parentPoint;
auto point = parentView->convertFromContainingViewToRenderer(renderer.get(), parentPoint);
auto contentBoxLocation = renderer->contentBoxLocation();
point.move(-contentBoxLocation.x(), -contentBoxLocation.y());
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;
}
}