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