blob: 35b94475eb6702eb2d55e38e0e2ea3a8f90eae45 [file] [log] [blame]
Michael Ludwig6d1c0d42019-09-04 17:39:42 -04001/*
2 * Copyright 2019 Google LLC
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "samplecode/Sample.h"
9
10#include "include/core/SkCanvas.h"
11#include "include/core/SkColor.h"
12#include "include/core/SkFont.h"
13#include "include/core/SkPaint.h"
14#include "include/core/SkPath.h"
15#include "include/core/SkPoint.h"
16#include "include/core/SkRect.h"
17
18#include "tools/ToolUtils.h"
19
Michael Ludwig6d1c0d42019-09-04 17:39:42 -040020static constexpr float kLineHeight = 16.f;
21static constexpr float kLineInset = 8.f;
22
23static float print_size(SkCanvas* canvas, const char* prefix, const SkIRect& rect,
Michael Ludwigb6e89222019-09-05 13:10:21 -040024 float x, float y, const SkFont& font, const SkPaint& paint) {
Michael Ludwig6d1c0d42019-09-04 17:39:42 -040025 canvas->drawString(prefix, x, y, font, paint);
26 y += kLineHeight;
27 SkString sz;
28 sz.appendf("%d x %d", rect.width(), rect.height());
29 canvas->drawString(sz, x, y, font, paint);
30 return y + kLineHeight;
31}
32
Michael Ludwigb6e89222019-09-05 13:10:21 -040033static float print_info(SkCanvas* canvas, const SkIRect& origLayerBounds,
34 const SkIRect& localLayerBounds, const SkIRect& filterInputBounds,
35 const SkIRect& devLayerBounds) {
Michael Ludwig6d1c0d42019-09-04 17:39:42 -040036 SkFont font(nullptr, 12);
37 SkPaint text;
38 text.setAntiAlias(true);
39
40 float y = kLineHeight;
41
42 text.setColor(SK_ColorBLACK);
43 y = print_size(canvas, "Orig layer", origLayerBounds, kLineInset, y, font, text);
44 text.setColor(SK_ColorRED);
45 y = print_size(canvas, "Filter layer", localLayerBounds, kLineInset, y, font, text);
46 text.setColor(SK_ColorBLUE);
47 y = print_size(canvas, "Filter input", filterInputBounds, kLineInset, y, font, text);
48 text.setColor(SK_ColorMAGENTA);
49 y = print_size(canvas, "Backdrop size", devLayerBounds, kLineInset, y, font, text);
50
51 return y;
52}
53
54static SkPaint line_paint(SkScalar width, SkColor color) {
55 SkPaint paint;
56 paint.setColor(color);
57 paint.setStrokeWidth(width);
58 paint.setStyle(SkPaint::kStroke_Style);
59 paint.setAntiAlias(true);
60 return paint;
61}
62
63class BackdropBoundsSample : public Sample {
64public:
65 BackdropBoundsSample() {}
66
67 void onDrawContent(SkCanvas* canvas) override {
68 SkMatrix ctm = canvas->getTotalMatrix();
69
70 // This decomposition is for the backdrop filtering, and does not represent the CTM that
71 // the layer actually uses (unless it also has a filter during restore).
72 SkMatrix toGlobal, layerMatrix;
73 SkSize scale;
74 if (ctm.isScaleTranslate()) {
75 // No decomposition needed
76 toGlobal = SkMatrix::I();
77 layerMatrix = ctm;
78 } else if (ctm.decomposeScale(&scale, &toGlobal)) {
Mike Reed1f607332020-05-21 12:11:27 -040079 layerMatrix = SkMatrix::Scale(scale.fWidth, scale.fHeight);
Michael Ludwig6d1c0d42019-09-04 17:39:42 -040080 } else {
81 toGlobal = ctm;
82 layerMatrix = SkMatrix::I();
83 }
84
85 SkMatrix fromGlobal;
86 if (!toGlobal.invert(&fromGlobal)) {
87 SkDebugf("Unable to invert CTM\n");
88 return;
89 }
90
91 // The local content, e.g. what would be submitted to drawRect
92 const SkRect localContentRect = SkRect::MakeLTRB(45.5f, 23.123f, 150.f, 140.45f);
93 canvas->drawRect(localContentRect, line_paint(0.f, SK_ColorBLACK));
94
95 canvas->save();
96 // The layer bounds of the content, this is the size of the actual layer and does not
97 // reflect the backdrop specific decomposition.
98 canvas->setMatrix(SkMatrix::I());
99 SkIRect origLayerBounds = ctm.mapRect(localContentRect).roundOut();
100 canvas->drawRect(SkRect::Make(origLayerBounds), line_paint(1.f, SK_ColorBLACK));
101
102 // Have to undo the full CTM transform on the layer bounds to get the layer bounds
103 // for the specific backdrop filter decomposition
104 canvas->setMatrix(toGlobal);
105 SkIRect layerBounds = fromGlobal.mapRect(SkRect::Make(origLayerBounds)).roundOut();
106 canvas->drawRect(SkRect::Make(layerBounds), line_paint(0.5f, SK_ColorRED));
107
108 // Input bounds for the backdrop filter to cover the actual layer bounds (emulate some
109 // blur that must outset by 5px for reading on the edge).
110 SkIRect filterInputBounds = layerBounds;
111 filterInputBounds.outset(5, 5);
112 canvas->drawRect(SkRect::Make(filterInputBounds), line_paint(1.f, SK_ColorBLUE));
113
Michael Ludwig6d1c0d42019-09-04 17:39:42 -0400114 // The destination bounds that must be snapped in order to transform and fill the
115 // filterInputBounds
116 canvas->setMatrix(SkMatrix::I());
117 SkIRect devLayerBounds = toGlobal.mapRect(SkRect::Make(filterInputBounds)).roundOut();
118 canvas->drawRect(SkRect::Make(devLayerBounds), line_paint(2.f, SK_ColorMAGENTA));
119
120 // The destination bounds mapped back into the layer space, which should cover 'layerBounds'
121 SkPath backdropCoveringBounds;
122
123 // Add axis lines, to show perspective distortion
124 SkIRect local = fromGlobal.mapRect(SkRect::Make(devLayerBounds)).roundOut();
125 static int kAxisSpace = 10;
126 for (int y = local.fTop + kAxisSpace; y <= local.fBottom - kAxisSpace; y += kAxisSpace) {
127 backdropCoveringBounds.moveTo(local.fLeft, y);
128 backdropCoveringBounds.lineTo(local.fRight, y);
129 }
130 for (int x = local.fLeft + kAxisSpace; x <= local.fRight - kAxisSpace; x += kAxisSpace) {
131 backdropCoveringBounds.moveTo(x, local.fTop);
132 backdropCoveringBounds.lineTo(x, local.fBottom);
133 }
134
135 canvas->setMatrix(toGlobal);
136 canvas->drawPath(backdropCoveringBounds, line_paint(0.f, SK_ColorGREEN));
137
138 canvas->resetMatrix();
139 print_info(canvas, origLayerBounds, layerBounds, filterInputBounds, devLayerBounds);
140
141 canvas->restore();
142 }
143
144 SkString name() override { return SkString("BackdropBounds"); }
145
146private:
147
John Stiles7571f9e2020-09-02 22:42:33 -0400148 using INHERITED = Sample;
Michael Ludwig6d1c0d42019-09-04 17:39:42 -0400149};
150
151DEF_SAMPLE(return new BackdropBoundsSample();)