blob: 6faf06729645b40c6d3f3119b77fd75b9de16fcc [file] [log] [blame]
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "third_party/blink/renderer/modules/delegated_ink/delegated_ink_trail_presenter.h"
#include "components/viz/common/delegated_ink_metadata.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_pointer_event_init.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_ink_trail_style.h"
#include "third_party/blink/renderer/core/dom/element.h"
#include "third_party/blink/renderer/core/events/pointer_event.h"
#include "third_party/blink/renderer/core/frame/local_frame.h"
#include "third_party/blink/renderer/core/html/html_iframe_element.h"
#include "third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h"
#include "third_party/blink/renderer/core/testing/sim/sim_request.h"
#include "third_party/blink/renderer/core/testing/sim/sim_test.h"
namespace blink {
namespace {
class TestDelegatedInkMetadata {
public:
explicit TestDelegatedInkMetadata(viz::DelegatedInkMetadata* metadata)
: point_(metadata->point()),
color_(metadata->color()),
diameter_(metadata->diameter()),
area_(metadata->presentation_area()),
is_hovering_(metadata->is_hovering()) {}
explicit TestDelegatedInkMetadata(gfx::RectF area,
float device_pixel_ratio = 1.0)
: area_(area) {
area_.Scale(device_pixel_ratio);
}
TestDelegatedInkMetadata() = default;
void ExpectEqual(TestDelegatedInkMetadata actual) const {
// LayoutUnits cast floats to ints, causing the actual point and area to be
// off a small amount from what is expected.
EXPECT_NEAR(point_.x(), actual.point_.x(), LayoutUnit::Epsilon());
EXPECT_NEAR(point_.y(), actual.point_.y(), LayoutUnit::Epsilon());
EXPECT_EQ(color_, actual.color_);
EXPECT_EQ(diameter_, actual.diameter_);
EXPECT_NEAR(area_.x(), actual.area_.x(), LayoutUnit::Epsilon());
EXPECT_NEAR(area_.y(), actual.area_.y(), LayoutUnit::Epsilon());
EXPECT_NEAR(area_.width(), actual.area_.width(), LayoutUnit::Epsilon());
EXPECT_NEAR(area_.height(), actual.area_.height(), LayoutUnit::Epsilon());
EXPECT_EQ(is_hovering_, actual.is_hovering_);
}
void SetPoint(gfx::PointF pt) { point_ = pt; }
void SetColor(SkColor color) { color_ = color; }
void SetDiameter(double diameter) { diameter_ = diameter; }
void SetArea(gfx::RectF area) { area_ = area; }
void SetHovering(bool hovering) { is_hovering_ = hovering; }
private:
gfx::PointF point_;
SkColor color_;
double diameter_;
gfx::RectF area_;
bool is_hovering_;
};
DelegatedInkTrailPresenter* CreatePresenter(Element* element,
LocalFrame* frame) {
return DelegatedInkTrailPresenter::CreatePresenter(element, frame);
}
} // namespace
class DelegatedInkTrailPresenterUnitTest : public SimTest {
public:
void SetWebViewSize(float width, float height) {
WebView().MainFrameViewWidget()->Resize(gfx::Size(width, height));
}
void SetWebViewSizeGreaterThanCanvas(float width, float height) {
// The presentation area is intersected with the visible content rect, so
// make sure that the page size is larger than the canvas to ensure it
// isn't clipped. Adding 1 to the height and width is enough to ensure that
// doesn't happen.
SetWebViewSize(width + 1, height + 1);
}
PointerEvent* CreatePointerMoveEvent(gfx::PointF pt, bool hovering) {
PointerEventInit* init = PointerEventInit::Create();
init->setClientX(pt.x());
init->setClientY(pt.y());
if (!hovering) {
init->setButtons(MouseEvent::WebInputEventModifiersToButtons(
WebInputEvent::Modifiers::kLeftButtonDown));
}
PointerEvent* event = PointerEvent::Create("pointermove", init);
event->SetTrusted(true);
return event;
}
TestDelegatedInkMetadata GetActualMetadata() {
return TestDelegatedInkMetadata(WebView()
.MainFrameViewWidget()
->LayerTreeHostForTesting()
->DelegatedInkMetadataForTesting());
}
void SetPageZoomFactor(const float zoom) {
GetDocument().GetFrame()->SetPageZoomFactor(zoom);
}
};
// Test scenarios with the presentation area extending beyond the edges of the
// window to confirm it gets clipped correctly.
class DelegatedInkTrailPresenterCanvasBeyondViewport
: public DelegatedInkTrailPresenterUnitTest,
public testing::WithParamInterface<bool> {
public:
bool CanvasShouldBePastViewport() { return GetParam(); }
float GetViewportWidth() const { return kViewportWidth; }
float GetViewportHeight() const { return kViewportHeight; }
void SetWebViewSize() {
DelegatedInkTrailPresenterUnitTest::SetWebViewSize(kViewportWidth,
kViewportHeight);
}
private:
const float kViewportWidth = 175.f;
const float kViewportHeight = 180.f;
};
// Confirm that all the information is collected and transformed correctly, if
// necessary. Numbers and color used were chosen arbitrarily.
TEST_P(DelegatedInkTrailPresenterCanvasBeyondViewport,
CollectAndPropagateMetadata) {
SimRequest main_resource("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
main_resource.Complete(R"HTML(
<!DOCTYPE html>
<style>
body {
margin: 0;
}
canvas {
width: 191px;
height: 234px;
}
</style>
<canvas id='canvas'></canvas>
)HTML");
Compositor().BeginFrame();
const float kCanvasWidth = 191.f;
const float kCanvasHeight = 234.f;
TestDelegatedInkMetadata expected_metadata;
if (!CanvasShouldBePastViewport()) {
SetWebViewSizeGreaterThanCanvas(kCanvasWidth, kCanvasHeight);
expected_metadata.SetArea(gfx::RectF(0, 0, kCanvasWidth, kCanvasHeight));
} else {
SetWebViewSize();
expected_metadata.SetArea(
gfx::RectF(0, 0, GetViewportWidth(), GetViewportHeight()));
}
DelegatedInkTrailPresenter* presenter = CreatePresenter(
GetDocument().getElementById("canvas"), GetDocument().GetFrame());
DCHECK(presenter);
InkTrailStyle style;
style.setDiameter(5);
style.setColor("blue");
expected_metadata.SetDiameter(style.diameter());
expected_metadata.SetColor(SK_ColorBLUE);
gfx::PointF pt(100, 100);
presenter->updateInkTrailStartPoint(
ToScriptStateForMainWorld(GetDocument().GetFrame()),
CreatePointerMoveEvent(pt, /*hovering*/ true), &style);
expected_metadata.SetHovering(true);
expected_metadata.SetPoint(pt);
expected_metadata.ExpectEqual(GetActualMetadata());
}
// Confirm that everything is still calculated correctly when the
// DevicePixelRatio is not 1. Numbers and color used were chosen arbitrarily.
TEST_P(DelegatedInkTrailPresenterCanvasBeyondViewport,
NotDefaultDevicePixelRatio) {
const float kZoom = 1.7;
SetPageZoomFactor(kZoom);
SimRequest main_resource("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
main_resource.Complete(R"HTML(
<!DOCTYPE html>
<style>
body {
margin: 0;
}
canvas {
width: 281px;
height: 190px;
}
</style>
<canvas id='canvas'></canvas>
)HTML");
Compositor().BeginFrame();
const float kCanvasWidth = 281.f;
const float kCanvasHeight = 190.f;
TestDelegatedInkMetadata expected_metadata;
if (!CanvasShouldBePastViewport()) {
SetWebViewSizeGreaterThanCanvas(kCanvasWidth * kZoom,
kCanvasHeight * kZoom);
expected_metadata = TestDelegatedInkMetadata(
gfx::RectF(0, 0, kCanvasWidth, kCanvasHeight), kZoom);
} else {
SetWebViewSize();
expected_metadata.SetArea(
gfx::RectF(0, 0, GetViewportWidth(), GetViewportHeight()));
}
DelegatedInkTrailPresenter* presenter = CreatePresenter(
GetDocument().getElementById("canvas"), GetDocument().GetFrame());
DCHECK(presenter);
InkTrailStyle style;
style.setDiameter(101.5);
style.setColor("magenta");
expected_metadata.SetDiameter(style.diameter() * kZoom);
expected_metadata.SetColor(SK_ColorMAGENTA);
gfx::PointF pt(87, 113);
presenter->updateInkTrailStartPoint(
ToScriptStateForMainWorld(GetDocument().GetFrame()),
CreatePointerMoveEvent(pt, /*hovering*/ true), &style);
expected_metadata.SetHovering(true);
pt.Scale(kZoom);
expected_metadata.SetPoint(pt);
expected_metadata.ExpectEqual(GetActualMetadata());
}
// Confirm that the offset is correct. Numbers and color used were chosen
// arbitrarily.
TEST_P(DelegatedInkTrailPresenterCanvasBeyondViewport, CanvasNotAtOrigin) {
SimRequest main_resource("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
main_resource.Complete(R"HTML(
<!DOCTYPE html>
<style>
body {
margin: 0;
}
canvas {
width: 250px;
height: 350px;
position: fixed;
top: 59px;
left: 16px;
}
</style>
<canvas id='canvas'></canvas>
)HTML");
Compositor().BeginFrame();
const float kCanvasWidth = 250.f;
const float kCanvasHeight = 350.f;
const float kCanvasTopOffset = 59.f;
const float kCanvasLeftOffset = 16.f;
TestDelegatedInkMetadata expected_metadata;
if (!CanvasShouldBePastViewport()) {
SetWebViewSizeGreaterThanCanvas(kCanvasWidth + kCanvasLeftOffset,
kCanvasHeight + kCanvasTopOffset);
expected_metadata.SetArea(gfx::RectF(kCanvasLeftOffset, kCanvasTopOffset,
kCanvasWidth, kCanvasHeight));
} else {
SetWebViewSize();
expected_metadata.SetArea(
gfx::RectF(kCanvasLeftOffset, kCanvasTopOffset,
GetViewportWidth() - kCanvasLeftOffset,
GetViewportHeight() - kCanvasTopOffset));
}
DelegatedInkTrailPresenter* presenter = CreatePresenter(
GetDocument().getElementById("canvas"), GetDocument().GetFrame());
DCHECK(presenter);
InkTrailStyle style;
style.setDiameter(8.6);
style.setColor("red");
expected_metadata.SetDiameter(style.diameter());
expected_metadata.SetColor(SK_ColorRED);
gfx::PointF pt(380, 175);
presenter->updateInkTrailStartPoint(
ToScriptStateForMainWorld(GetDocument().GetFrame()),
CreatePointerMoveEvent(pt, /*hovering*/ false), &style);
expected_metadata.SetHovering(false);
expected_metadata.SetPoint(pt);
expected_metadata.ExpectEqual(GetActualMetadata());
}
// Confirm that values, specifically offsets, are transformed correctly when
// the canvas is in an iframe. Numbers and color used were chosen arbitrarily.
TEST_P(DelegatedInkTrailPresenterCanvasBeyondViewport, CanvasInIFrame) {
SimRequest main_resource("https://example.com/test.html", "text/html");
SimRequest frame_resource("https://example.com/iframe.html", "text/html");
LoadURL("https://example.com/test.html");
main_resource.Complete(R"HTML(
<!DOCTYPE html>
<style>
body {
margin: 0;
}
#iframe {
width: 500px;
height: 500px;
position: fixed;
top: 26px;
left: 57px;
}
</style>
<iframe id='iframe' src='https://example.com/iframe.html'>
</iframe>
)HTML");
frame_resource.Complete(R"HTML(
<!DOCTYPE html>
<style>
body {
margin: 0;
}
canvas {
width: 250px;
height: 250px;
position: fixed;
top: 33px;
left: 16px;
}
</style>
<canvas id='canvas'></canvas>
)HTML");
Compositor().BeginFrame();
// When creating the expected metadata, we have to take into account the
// offsets that are applied to the iframe that the canvas is in, and the 2px
// border around the iframe.
const float kIframeBorder = 2.f;
const float kIframeLeftOffset = 57.f + kIframeBorder;
const float kIframeTopOffset = 26.f + kIframeBorder;
const float kIframeHeight = 500.f;
const float kIframeWidth = 500.f;
const float kCanvasLeftOffset = 16.f;
const float kCanvasTopOffset = 33.f;
const float kCanvasHeight = 250.f;
const float kCanvasWidth = 250.f;
TestDelegatedInkMetadata expected_metadata;
if (!CanvasShouldBePastViewport()) {
SetWebViewSizeGreaterThanCanvas(kIframeWidth + kIframeLeftOffset,
kIframeHeight + kIframeTopOffset);
expected_metadata.SetArea(gfx::RectF(kIframeLeftOffset + kCanvasLeftOffset,
kIframeTopOffset + kCanvasTopOffset,
kCanvasWidth, kCanvasHeight));
} else {
SetWebViewSize();
expected_metadata.SetArea(gfx::RectF(
kIframeLeftOffset + kCanvasLeftOffset,
kIframeTopOffset + kCanvasTopOffset,
GetViewportWidth() - (kIframeLeftOffset + kCanvasLeftOffset),
GetViewportHeight() - (kIframeTopOffset + kCanvasTopOffset)));
}
auto* iframe_element =
To<HTMLIFrameElement>(GetDocument().getElementById("iframe"));
auto* iframe_localframe = To<LocalFrame>(iframe_element->ContentFrame());
Document* iframe_document = iframe_element->contentDocument();
DelegatedInkTrailPresenter* presenter = CreatePresenter(
iframe_localframe->GetDocument()->getElementById("canvas"),
iframe_document->GetFrame());
DCHECK(presenter);
InkTrailStyle style;
style.setDiameter(0.3);
style.setColor("cyan");
expected_metadata.SetDiameter(style.diameter());
expected_metadata.SetColor(SK_ColorCYAN);
gfx::PointF pt(380, 375);
presenter->updateInkTrailStartPoint(
ToScriptStateForMainWorld(iframe_document->GetFrame()),
CreatePointerMoveEvent(pt, /*hovering*/ false), &style);
expected_metadata.SetHovering(false);
expected_metadata.SetPoint(
gfx::PointF(pt.x() + kIframeLeftOffset, pt.y() + kIframeTopOffset));
expected_metadata.ExpectEqual(GetActualMetadata());
}
// Confirm that values, specifically offsets, are transformed correctly when
// the canvas is in a nested iframe. Numbers and color used were chosen
// arbitrarily.
TEST_P(DelegatedInkTrailPresenterCanvasBeyondViewport, NestedIframe) {
SimRequest main_resource("https://example.com/test.html", "text/html");
SimRequest frame_resource("https://example.com/iframe.html", "text/html");
SimRequest frame2_resource("https://example.com/iframe2.html", "text/html");
LoadURL("https://example.com/test.html");
main_resource.Complete(R"HTML(
<!DOCTYPE html>
<style>
body {
margin: 0;
}
#OuterIframe {
width: 500px;
height: 500px;
position: fixed;
top: 26px;
left: 57px;
}
</style>
<iframe id='OuterIframe' src='https://example.com/iframe.html'>
</iframe>
)HTML");
frame_resource.Complete(R"HTML(
<!DOCTYPE html>
<style>
body {
margin: 0;
}
#InnerIframe {
width: 400px;
height: 400px;
position: fixed;
top: 11px;
left: 18px;
}
</style>
<iframe id='InnerIframe' src='https://example.com/iframe2.html'>
</iframe>
)HTML");
frame2_resource.Complete(R"HTML(
<!DOCTYPE html>
<style>
body {
margin: 0;
}
canvas {
width: 250px;
height: 250px;
position: fixed;
top: 28px;
left: 6px;
}
</style>
<canvas id='canvas'></canvas>
)HTML");
Compositor().BeginFrame();
// When creating the expected metadata, we have to take into account the
// offsets that are applied to the iframe that the canvas is in, and the 2px
// border around the iframe.
const float kIframeBorder = 2.f;
const float kOuterIframeLeftOffset = 57.f + kIframeBorder;
const float kOuterIframeTopOffset = 26.f + kIframeBorder;
const float kOuterIframeHeight = 500.f;
const float kOuterIframeWidth = 500.f;
const float kInnerIframeLeftOffset =
kOuterIframeLeftOffset + 18.f + kIframeBorder;
const float kInnerIframeTopOffset =
kOuterIframeTopOffset + 11.f + kIframeBorder;
const float kCanvasLeftOffset = 6.f;
const float kCanvasTopOffset = 28.f;
const float kCanvasHeight = 250.f;
const float kCanvasWidth = 250.f;
TestDelegatedInkMetadata expected_metadata;
if (!CanvasShouldBePastViewport()) {
SetWebViewSizeGreaterThanCanvas(kOuterIframeWidth + kOuterIframeLeftOffset,
kOuterIframeHeight + kOuterIframeTopOffset);
expected_metadata.SetArea(gfx::RectF(
kInnerIframeLeftOffset + kCanvasLeftOffset,
kInnerIframeTopOffset + kCanvasTopOffset, kCanvasWidth, kCanvasHeight));
} else {
SetWebViewSize();
expected_metadata.SetArea(gfx::RectF(
kInnerIframeLeftOffset + kCanvasLeftOffset,
kInnerIframeTopOffset + kCanvasTopOffset,
GetViewportWidth() - (kInnerIframeLeftOffset + kCanvasLeftOffset),
GetViewportHeight() - (kInnerIframeTopOffset + kCanvasTopOffset)));
}
auto* outer_iframe_element =
To<HTMLIFrameElement>(GetDocument().getElementById("OuterIframe"));
auto* inner_iframe_element = To<HTMLIFrameElement>(
outer_iframe_element->contentDocument()->getElementById("InnerIframe"));
auto* iframe_localframe =
To<LocalFrame>(inner_iframe_element->ContentFrame());
Document* iframe_document = inner_iframe_element->contentDocument();
DelegatedInkTrailPresenter* presenter = CreatePresenter(
iframe_localframe->GetDocument()->getElementById("canvas"),
iframe_document->GetFrame());
DCHECK(presenter);
InkTrailStyle style;
style.setDiameter(100000.3);
style.setColor("yellow");
expected_metadata.SetDiameter(style.diameter());
expected_metadata.SetColor(SK_ColorYELLOW);
gfx::PointF pt(350, 375);
presenter->updateInkTrailStartPoint(
ToScriptStateForMainWorld(iframe_document->GetFrame()),
CreatePointerMoveEvent(pt, /*hovering*/ true), &style);
expected_metadata.SetHovering(true);
expected_metadata.SetPoint(gfx::PointF(pt.x() + kInnerIframeLeftOffset,
pt.y() + kInnerIframeTopOffset));
expected_metadata.ExpectEqual(GetActualMetadata());
}
// Confirm that values are correct when an iframe is used and presentation area
// isn't provided. Numbers and color used were chosen arbitrarily.
TEST_P(DelegatedInkTrailPresenterCanvasBeyondViewport,
IFrameNoPresentationArea) {
SimRequest main_resource("https://example.com/test.html", "text/html");
SimRequest frame_resource("https://example.com/iframe.html", "text/html");
LoadURL("https://example.com/test.html");
main_resource.Complete(R"HTML(
<!DOCTYPE html>
<style>
body {
margin: 0;
}
#iframe {
width: 500px;
height: 500px;
position: fixed;
top: 56px;
left: 72px;
}
</style>
<iframe id='iframe' src='https://example.com/iframe.html'>
</iframe>
)HTML");
frame_resource.Complete(R"HTML(
<!DOCTYPE html>
<style>
body {
margin: 0;
}
</style>
)HTML");
Compositor().BeginFrame();
// When creating the expected metadata, we have to take into account the
// offsets that are applied to the iframe, and the 2px border.
const float kIframeBorder = 2.f;
const float kIframeLeftOffset = 72.f + kIframeBorder;
const float kIframeTopOffset = 56.f + kIframeBorder;
const float kIframeHeight = 500.f;
const float kIframeWidth = 500.f;
TestDelegatedInkMetadata expected_metadata;
if (!CanvasShouldBePastViewport()) {
SetWebViewSizeGreaterThanCanvas(kIframeWidth + kIframeLeftOffset,
kIframeHeight + kIframeTopOffset);
expected_metadata.SetArea(gfx::RectF(kIframeLeftOffset, kIframeTopOffset,
kIframeWidth, kIframeHeight));
} else {
SetWebViewSize();
expected_metadata.SetArea(
gfx::RectF(kIframeLeftOffset, kIframeTopOffset,
GetViewportWidth() - kIframeLeftOffset,
GetViewportHeight() - kIframeTopOffset));
}
Document* iframe_document =
To<HTMLIFrameElement>(GetDocument().getElementById("iframe"))
->contentDocument();
DelegatedInkTrailPresenter* presenter =
CreatePresenter(nullptr, iframe_document->GetFrame());
DCHECK(presenter);
InkTrailStyle style;
style.setDiameter(0.01);
style.setColor("white");
expected_metadata.SetDiameter(style.diameter());
expected_metadata.SetColor(SK_ColorWHITE);
gfx::PointF pt(380, 375);
presenter->updateInkTrailStartPoint(
ToScriptStateForMainWorld(iframe_document->GetFrame()),
CreatePointerMoveEvent(pt, /*hovering*/ true), &style);
expected_metadata.SetHovering(true);
expected_metadata.SetPoint(
gfx::PointF(pt.x() + kIframeLeftOffset, pt.y() + kIframeTopOffset));
expected_metadata.ExpectEqual(GetActualMetadata());
}
INSTANTIATE_TEST_SUITE_P(,
DelegatedInkTrailPresenterCanvasBeyondViewport,
testing::Bool());
// Confirm that presentation area defaults to the size of the viewport.
// Numbers and color used were chosen arbitrarily.
TEST_F(DelegatedInkTrailPresenterUnitTest, PresentationAreaNotProvided) {
const int kViewportHeight = 555;
const int kViewportWidth = 333;
SetWebViewSize(kViewportWidth, kViewportHeight);
DelegatedInkTrailPresenter* presenter =
CreatePresenter(nullptr, GetDocument().GetFrame());
DCHECK(presenter);
TestDelegatedInkMetadata expected_metadata(
gfx::RectF(0, 0, kViewportWidth, kViewportHeight));
InkTrailStyle style;
style.setDiameter(3.6);
style.setColor("yellow");
expected_metadata.SetDiameter(style.diameter());
expected_metadata.SetColor(SK_ColorYELLOW);
gfx::PointF pt(70, 109);
presenter->updateInkTrailStartPoint(
ToScriptStateForMainWorld(GetDocument().GetFrame()),
CreatePointerMoveEvent(pt, /*hovering*/ false), &style);
expected_metadata.SetHovering(false);
expected_metadata.SetPoint(pt);
expected_metadata.ExpectEqual(GetActualMetadata());
}
// Test that the presentation area is clipped correctly by the dimensions of
// the iframe, even when the iframe and canvas each fit entirely within the
// visual viewport.
TEST_F(DelegatedInkTrailPresenterUnitTest, CanvasExtendsOutsideOfIframe) {
SimRequest main_resource("https://example.com/test.html", "text/html");
SimRequest frame_resource("https://example.com/iframe.html", "text/html");
LoadURL("https://example.com/test.html");
main_resource.Complete(R"HTML(
<!DOCTYPE html>
<style>
body {
margin: 0;
}
#iframe {
width: 150px;
height: 150px;
position: fixed;
top: 13px;
left: 19px;
}
</style>
<iframe id='iframe' src='https://example.com/iframe.html'>
</iframe>
)HTML");
frame_resource.Complete(R"HTML(
<!DOCTYPE html>
<style>
body {
margin: 0;
}
canvas {
width: 199px;
height: 202px;
}
</style>
<canvas id='canvas'></canvas>
)HTML");
Compositor().BeginFrame();
// When creating the expected metadata, we have to take into account the
// offsets that are applied to the iframe that the canvas is in, and the 2px
// border around the iframe.
const float kIframeBorder = 2.f;
const float kIframeLeftOffset = 19.f + kIframeBorder;
const float kIframeTopOffset = 13.f + kIframeBorder;
const float kIframeHeight = 150.f;
const float kIframeWidth = 150.f;
const float kCanvasHeight = 202.f;
const float kCanvasWidth = 199.f;
// Ensure that the webpage is larger than the iframe and canvas.
SetWebViewSize(kCanvasWidth + kIframeLeftOffset + 1,
kCanvasHeight + kIframeTopOffset + 1);
TestDelegatedInkMetadata expected_metadata(gfx::RectF(
kIframeLeftOffset, kIframeTopOffset, kIframeWidth, kIframeHeight));
auto* iframe_element =
To<HTMLIFrameElement>(GetDocument().getElementById("iframe"));
auto* iframe_localframe = To<LocalFrame>(iframe_element->ContentFrame());
Document* iframe_document = iframe_element->contentDocument();
DelegatedInkTrailPresenter* presenter = CreatePresenter(
iframe_localframe->GetDocument()->getElementById("canvas"),
iframe_document->GetFrame());
DCHECK(presenter);
InkTrailStyle style;
style.setDiameter(99.999);
style.setColor("lime");
expected_metadata.SetDiameter(style.diameter());
expected_metadata.SetColor(SK_ColorGREEN);
gfx::PointF pt(102, 67);
presenter->updateInkTrailStartPoint(
ToScriptStateForMainWorld(iframe_document->GetFrame()),
CreatePointerMoveEvent(pt, /*hovering*/ false), &style);
expected_metadata.SetHovering(false);
expected_metadata.SetPoint(
gfx::PointF(pt.x() + kIframeLeftOffset, pt.y() + kIframeTopOffset));
expected_metadata.ExpectEqual(GetActualMetadata());
}
// Test that the presentation area is clipped correctly when it is offset left
// and above the iframe boundaries.
TEST_F(DelegatedInkTrailPresenterUnitTest, CanvasLeftAndAboveIframeBoundaries) {
SimRequest main_resource("https://example.com/test.html", "text/html");
SimRequest frame_resource("https://example.com/iframe.html", "text/html");
LoadURL("https://example.com/test.html");
main_resource.Complete(R"HTML(
<!DOCTYPE html>
<style>
body {
margin: 0;
}
#iframe {
width: 300px;
height: 301px;
position: fixed;
top: 13px;
left: 19px;
}
</style>
<iframe id='iframe' src='https://example.com/iframe.html'>
</iframe>
)HTML");
frame_resource.Complete(R"HTML(
<!DOCTYPE html>
<style>
body {
margin: 0;
}
canvas {
width: 189px;
height: 145px;
position: fixed;
top: -70px;
left: -99px;
}
</style>
<canvas id='canvas'></canvas>
)HTML");
Compositor().BeginFrame();
// When creating the expected metadata, we have to take into account the
// offsets that are applied to the iframe that the canvas is in, and the 2px
// border around the iframe.
const float kIframeBorder = 2.f;
const float kIframeLeftOffset = 19.f + kIframeBorder;
const float kIframeTopOffset = 13.f + kIframeBorder;
const float kIframeHeight = 301.f;
const float kIframeWidth = 300.f;
const float kCanvasHeight = 145.f;
const float kCanvasWidth = 189.f;
const float kCanvasLeftOffset = -99.f;
const float kCanvasTopOffset = -70.f;
// Ensure that the webpage is larger than the iframe.
SetWebViewSize(kIframeHeight + kIframeLeftOffset + 1,
kIframeWidth + kIframeTopOffset + 1);
TestDelegatedInkMetadata expected_metadata(gfx::RectF(
kIframeLeftOffset, kIframeTopOffset, kCanvasWidth + kCanvasLeftOffset,
kCanvasHeight + kCanvasTopOffset));
auto* iframe_element =
To<HTMLIFrameElement>(GetDocument().getElementById("iframe"));
auto* iframe_localframe = To<LocalFrame>(iframe_element->ContentFrame());
Document* iframe_document = iframe_element->contentDocument();
DelegatedInkTrailPresenter* presenter = CreatePresenter(
iframe_localframe->GetDocument()->getElementById("canvas"),
iframe_document->GetFrame());
DCHECK(presenter);
InkTrailStyle style;
style.setDiameter(99.999);
style.setColor("lime");
expected_metadata.SetDiameter(style.diameter());
expected_metadata.SetColor(SK_ColorGREEN);
gfx::PointF pt(102, 67);
presenter->updateInkTrailStartPoint(
ToScriptStateForMainWorld(iframe_document->GetFrame()),
CreatePointerMoveEvent(pt, /*hovering*/ true), &style);
expected_metadata.SetHovering(true);
expected_metadata.SetPoint(
gfx::PointF(pt.x() + kIframeLeftOffset, pt.y() + kIframeTopOffset));
expected_metadata.ExpectEqual(GetActualMetadata());
}
// Confirm that values, specifically presentation area, are transformed
// correctly when the iframe that the canvas is in is clipped by its parent
// iframe. Numbers and color used were chosen arbitrarily.
TEST_F(DelegatedInkTrailPresenterUnitTest, OuterIframeClipsInnerIframe) {
SimRequest main_resource("https://example.com/test.html", "text/html");
SimRequest frame_resource("https://example.com/iframe.html", "text/html");
SimRequest frame2_resource("https://example.com/iframe2.html", "text/html");
LoadURL("https://example.com/test.html");
main_resource.Complete(R"HTML(
<!DOCTYPE html>
<style>
body {
margin: 0;
}
#OuterIframe {
width: 500px;
height: 500px;
position: fixed;
top: 26px;
left: 57px;
}
</style>
<iframe id='OuterIframe' src='https://example.com/iframe.html'>
</iframe>
)HTML");
frame_resource.Complete(R"HTML(
<!DOCTYPE html>
<style>
body {
margin: 0;
}
#InnerIframe {
width: 400px;
height: 400px;
position: fixed;
top: 311px;
left: 334px;
}
</style>
<iframe id='InnerIframe' src='https://example.com/iframe2.html'>
</iframe>
)HTML");
frame2_resource.Complete(R"HTML(
<!DOCTYPE html>
<style>
body {
margin: 0;
}
canvas {
width: 250px;
height: 250px;
position: fixed;
top: 1px;
left: 2px;
}
</style>
<canvas id='canvas'></canvas>
)HTML");
Compositor().BeginFrame();
// When creating the expected metadata, we have to take into account the
// offsets that are applied to the iframe that the canvas is in, and the 2px
// border around the iframe.
const float kIframeBorder = 2.f;
const float kOuterIframeLeftOffset = 57.f + kIframeBorder;
const float kOuterIframeTopOffset = 26.f + kIframeBorder;
const float kOuterIframeHeight = 500.f;
const float kOuterIframeWidth = 500.f;
const float kInnerIframeLeftOffset =
kOuterIframeLeftOffset + 334.f + kIframeBorder;
const float kInnerIframeTopOffset =
kOuterIframeTopOffset + 311.f + kIframeBorder;
const float kCanvasLeftOffset = 2.f;
const float kCanvasTopOffset = 1.f;
// Ensure that the webpage is larger than the iframe and canvas.
const float kViewportWidth = kOuterIframeWidth + kOuterIframeLeftOffset + 1.f;
const float kViewportHeight =
kOuterIframeHeight + kOuterIframeTopOffset + 1.f;
SetWebViewSize(kViewportWidth, kViewportHeight);
TestDelegatedInkMetadata expected_metadata(
gfx::RectF(kInnerIframeLeftOffset + kCanvasLeftOffset,
kInnerIframeTopOffset + kCanvasTopOffset,
kOuterIframeWidth + kOuterIframeLeftOffset -
kInnerIframeLeftOffset - kCanvasLeftOffset,
kOuterIframeHeight + kOuterIframeTopOffset -
kInnerIframeTopOffset - kCanvasTopOffset));
auto* outer_iframe_element =
To<HTMLIFrameElement>(GetDocument().getElementById("OuterIframe"));
auto* inner_iframe_element = To<HTMLIFrameElement>(
outer_iframe_element->contentDocument()->getElementById("InnerIframe"));
auto* iframe_localframe =
To<LocalFrame>(inner_iframe_element->ContentFrame());
Document* iframe_document = inner_iframe_element->contentDocument();
DelegatedInkTrailPresenter* presenter = CreatePresenter(
iframe_localframe->GetDocument()->getElementById("canvas"),
iframe_document->GetFrame());
DCHECK(presenter);
InkTrailStyle style;
style.setDiameter(19);
style.setColor("red");
expected_metadata.SetDiameter(style.diameter());
expected_metadata.SetColor(SK_ColorRED);
gfx::PointF pt(357, 401);
presenter->updateInkTrailStartPoint(
ToScriptStateForMainWorld(iframe_document->GetFrame()),
CreatePointerMoveEvent(pt, /*hovering*/ false), &style);
expected_metadata.SetHovering(false);
expected_metadata.SetPoint(gfx::PointF(pt.x() + kInnerIframeLeftOffset,
pt.y() + kInnerIframeTopOffset));
expected_metadata.ExpectEqual(GetActualMetadata());
}
} // namespace blink