1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker * Copyright 2023 Google LLC
3*c8dee2aaSAndroid Build Coastguard Worker *
4*c8dee2aaSAndroid Build Coastguard Worker * Use of this source code is governed by a BSD-style license that can be
5*c8dee2aaSAndroid Build Coastguard Worker * found in the LICENSE file.
6*c8dee2aaSAndroid Build Coastguard Worker */
7*c8dee2aaSAndroid Build Coastguard Worker
8*c8dee2aaSAndroid Build Coastguard Worker #include "tools/gpu/TestCanvas.h"
9*c8dee2aaSAndroid Build Coastguard Worker
10*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkCanvas.h"
11*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkColorSpace.h" // IWYU pragma: keep
12*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkData.h"
13*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkImageInfo.h"
14*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRect.h"
15*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkTypes.h"
16*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkDebug.h"
17*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/chromium/SkChromeRemoteGlyphCache.h"
18*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/chromium/Slug.h"
19*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkCanvasPriv.h"
20*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkDevice.h"
21*c8dee2aaSAndroid Build Coastguard Worker #include "src/text/GlyphRun.h"
22*c8dee2aaSAndroid Build Coastguard Worker
23*c8dee2aaSAndroid Build Coastguard Worker #include <cstdint>
24*c8dee2aaSAndroid Build Coastguard Worker #include <memory>
25*c8dee2aaSAndroid Build Coastguard Worker #include <optional>
26*c8dee2aaSAndroid Build Coastguard Worker #include <vector>
27*c8dee2aaSAndroid Build Coastguard Worker
28*c8dee2aaSAndroid Build Coastguard Worker class SkPaint;
29*c8dee2aaSAndroid Build Coastguard Worker
30*c8dee2aaSAndroid Build Coastguard Worker namespace skiatest {
31*c8dee2aaSAndroid Build Coastguard Worker
TestCanvas(SkCanvas * canvas)32*c8dee2aaSAndroid Build Coastguard Worker TestCanvas<SkSlugTestKey>::TestCanvas(SkCanvas* canvas)
33*c8dee2aaSAndroid Build Coastguard Worker : SkCanvas(sk_ref_sp(canvas->rootDevice())) {}
34*c8dee2aaSAndroid Build Coastguard Worker
onDrawGlyphRunList(const sktext::GlyphRunList & glyphRunList,const SkPaint & paint)35*c8dee2aaSAndroid Build Coastguard Worker void TestCanvas<SkSlugTestKey>::onDrawGlyphRunList(
36*c8dee2aaSAndroid Build Coastguard Worker const sktext::GlyphRunList& glyphRunList, const SkPaint& paint) {
37*c8dee2aaSAndroid Build Coastguard Worker SkRect bounds = glyphRunList.sourceBoundsWithOrigin();
38*c8dee2aaSAndroid Build Coastguard Worker if (this->internalQuickReject(bounds, paint)) {
39*c8dee2aaSAndroid Build Coastguard Worker return;
40*c8dee2aaSAndroid Build Coastguard Worker }
41*c8dee2aaSAndroid Build Coastguard Worker auto layer = this->aboutToDraw(paint, &bounds);
42*c8dee2aaSAndroid Build Coastguard Worker if (layer) {
43*c8dee2aaSAndroid Build Coastguard Worker if (glyphRunList.hasRSXForm()) {
44*c8dee2aaSAndroid Build Coastguard Worker this->SkCanvas::onDrawGlyphRunList(glyphRunList, layer->paint());
45*c8dee2aaSAndroid Build Coastguard Worker } else {
46*c8dee2aaSAndroid Build Coastguard Worker auto slug = this->onConvertGlyphRunListToSlug(glyphRunList, layer->paint());
47*c8dee2aaSAndroid Build Coastguard Worker this->drawSlug(slug.get(), layer->paint());
48*c8dee2aaSAndroid Build Coastguard Worker }
49*c8dee2aaSAndroid Build Coastguard Worker }
50*c8dee2aaSAndroid Build Coastguard Worker }
51*c8dee2aaSAndroid Build Coastguard Worker
TestCanvas(SkCanvas * canvas)52*c8dee2aaSAndroid Build Coastguard Worker TestCanvas<SkSerializeSlugTestKey>::TestCanvas(SkCanvas* canvas)
53*c8dee2aaSAndroid Build Coastguard Worker : SkCanvas(sk_ref_sp(canvas->rootDevice())) {}
54*c8dee2aaSAndroid Build Coastguard Worker
onDrawGlyphRunList(const sktext::GlyphRunList & glyphRunList,const SkPaint & paint)55*c8dee2aaSAndroid Build Coastguard Worker void TestCanvas<SkSerializeSlugTestKey>::onDrawGlyphRunList(
56*c8dee2aaSAndroid Build Coastguard Worker const sktext::GlyphRunList& glyphRunList, const SkPaint& paint) {
57*c8dee2aaSAndroid Build Coastguard Worker SkRect bounds = glyphRunList.sourceBoundsWithOrigin();
58*c8dee2aaSAndroid Build Coastguard Worker if (this->internalQuickReject(bounds, paint)) {
59*c8dee2aaSAndroid Build Coastguard Worker return;
60*c8dee2aaSAndroid Build Coastguard Worker }
61*c8dee2aaSAndroid Build Coastguard Worker auto layer = this->aboutToDraw(paint, &bounds);
62*c8dee2aaSAndroid Build Coastguard Worker if (layer) {
63*c8dee2aaSAndroid Build Coastguard Worker if (glyphRunList.hasRSXForm()) {
64*c8dee2aaSAndroid Build Coastguard Worker this->SkCanvas::onDrawGlyphRunList(glyphRunList, layer->paint());
65*c8dee2aaSAndroid Build Coastguard Worker } else {
66*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkData> bytes;
67*c8dee2aaSAndroid Build Coastguard Worker {
68*c8dee2aaSAndroid Build Coastguard Worker auto slug = this->onConvertGlyphRunListToSlug(glyphRunList, layer->paint());
69*c8dee2aaSAndroid Build Coastguard Worker if (slug != nullptr) {
70*c8dee2aaSAndroid Build Coastguard Worker bytes = slug->serialize();
71*c8dee2aaSAndroid Build Coastguard Worker }
72*c8dee2aaSAndroid Build Coastguard Worker }
73*c8dee2aaSAndroid Build Coastguard Worker {
74*c8dee2aaSAndroid Build Coastguard Worker if (bytes != nullptr) {
75*c8dee2aaSAndroid Build Coastguard Worker auto slug = sktext::gpu::Slug::Deserialize(bytes->data(), bytes->size());
76*c8dee2aaSAndroid Build Coastguard Worker this->drawSlug(slug.get(), layer->paint());
77*c8dee2aaSAndroid Build Coastguard Worker }
78*c8dee2aaSAndroid Build Coastguard Worker }
79*c8dee2aaSAndroid Build Coastguard Worker }
80*c8dee2aaSAndroid Build Coastguard Worker }
81*c8dee2aaSAndroid Build Coastguard Worker }
82*c8dee2aaSAndroid Build Coastguard Worker
83*c8dee2aaSAndroid Build Coastguard Worker
84*c8dee2aaSAndroid Build Coastguard Worker // A do nothing handle manager for the remote strike server.
85*c8dee2aaSAndroid Build Coastguard Worker class ServerHandleManager : public SkStrikeServer::DiscardableHandleManager {
86*c8dee2aaSAndroid Build Coastguard Worker public:
createHandle()87*c8dee2aaSAndroid Build Coastguard Worker SkDiscardableHandleId createHandle() override {
88*c8dee2aaSAndroid Build Coastguard Worker return 0;
89*c8dee2aaSAndroid Build Coastguard Worker }
90*c8dee2aaSAndroid Build Coastguard Worker
lockHandle(SkDiscardableHandleId id)91*c8dee2aaSAndroid Build Coastguard Worker bool lockHandle(SkDiscardableHandleId id) override {
92*c8dee2aaSAndroid Build Coastguard Worker return true;
93*c8dee2aaSAndroid Build Coastguard Worker }
94*c8dee2aaSAndroid Build Coastguard Worker
isHandleDeleted(SkDiscardableHandleId id)95*c8dee2aaSAndroid Build Coastguard Worker bool isHandleDeleted(SkDiscardableHandleId id) override {
96*c8dee2aaSAndroid Build Coastguard Worker return false;
97*c8dee2aaSAndroid Build Coastguard Worker }
98*c8dee2aaSAndroid Build Coastguard Worker };
99*c8dee2aaSAndroid Build Coastguard Worker
100*c8dee2aaSAndroid Build Coastguard Worker // Lock the strikes into the cache for the length of the test. This handler is tied to the lifetime
101*c8dee2aaSAndroid Build Coastguard Worker // of the canvas used to render the entire test.
102*c8dee2aaSAndroid Build Coastguard Worker class ClientHandleManager : public SkStrikeClient::DiscardableHandleManager {
103*c8dee2aaSAndroid Build Coastguard Worker public:
deleteHandle(SkDiscardableHandleId id)104*c8dee2aaSAndroid Build Coastguard Worker bool deleteHandle(SkDiscardableHandleId id) override {
105*c8dee2aaSAndroid Build Coastguard Worker return fIsLocked;
106*c8dee2aaSAndroid Build Coastguard Worker }
107*c8dee2aaSAndroid Build Coastguard Worker
assertHandleValid(SkDiscardableHandleId id)108*c8dee2aaSAndroid Build Coastguard Worker void assertHandleValid(SkDiscardableHandleId id) override {
109*c8dee2aaSAndroid Build Coastguard Worker DiscardableHandleManager::assertHandleValid(id);
110*c8dee2aaSAndroid Build Coastguard Worker }
111*c8dee2aaSAndroid Build Coastguard Worker
notifyCacheMiss(SkStrikeClient::CacheMissType type,int fontSize)112*c8dee2aaSAndroid Build Coastguard Worker void notifyCacheMiss(SkStrikeClient::CacheMissType type, int fontSize) override {
113*c8dee2aaSAndroid Build Coastguard Worker
114*c8dee2aaSAndroid Build Coastguard Worker }
115*c8dee2aaSAndroid Build Coastguard Worker
notifyReadFailure(const ReadFailureData & data)116*c8dee2aaSAndroid Build Coastguard Worker void notifyReadFailure(const ReadFailureData& data) override {
117*c8dee2aaSAndroid Build Coastguard Worker DiscardableHandleManager::notifyReadFailure(data);
118*c8dee2aaSAndroid Build Coastguard Worker }
119*c8dee2aaSAndroid Build Coastguard Worker
unlock()120*c8dee2aaSAndroid Build Coastguard Worker void unlock() {
121*c8dee2aaSAndroid Build Coastguard Worker fIsLocked = true;
122*c8dee2aaSAndroid Build Coastguard Worker }
123*c8dee2aaSAndroid Build Coastguard Worker
124*c8dee2aaSAndroid Build Coastguard Worker private:
125*c8dee2aaSAndroid Build Coastguard Worker bool fIsLocked{false};
126*c8dee2aaSAndroid Build Coastguard Worker };
127*c8dee2aaSAndroid Build Coastguard Worker
TestCanvas(SkCanvas * canvas)128*c8dee2aaSAndroid Build Coastguard Worker TestCanvas<SkRemoteSlugTestKey>::TestCanvas(SkCanvas* canvas)
129*c8dee2aaSAndroid Build Coastguard Worker : SkCanvas(sk_ref_sp(canvas->rootDevice()))
130*c8dee2aaSAndroid Build Coastguard Worker , fServerHandleManager(new ServerHandleManager{})
131*c8dee2aaSAndroid Build Coastguard Worker , fClientHandleManager(new ClientHandleManager{})
132*c8dee2aaSAndroid Build Coastguard Worker , fStrikeServer(fServerHandleManager.get())
133*c8dee2aaSAndroid Build Coastguard Worker , fStrikeClient(fClientHandleManager) {}
134*c8dee2aaSAndroid Build Coastguard Worker
135*c8dee2aaSAndroid Build Coastguard Worker // Allow the strikes to be freed from the strike cache after the test has been drawn.
~TestCanvas()136*c8dee2aaSAndroid Build Coastguard Worker TestCanvas<SkRemoteSlugTestKey>::~TestCanvas() {
137*c8dee2aaSAndroid Build Coastguard Worker static_cast<ClientHandleManager*>(fClientHandleManager.get())->unlock();
138*c8dee2aaSAndroid Build Coastguard Worker }
139*c8dee2aaSAndroid Build Coastguard Worker
onDrawGlyphRunList(const sktext::GlyphRunList & glyphRunList,const SkPaint & paint)140*c8dee2aaSAndroid Build Coastguard Worker void TestCanvas<SkRemoteSlugTestKey>::onDrawGlyphRunList(
141*c8dee2aaSAndroid Build Coastguard Worker const sktext::GlyphRunList& glyphRunList, const SkPaint& paint) {
142*c8dee2aaSAndroid Build Coastguard Worker SkRect bounds = glyphRunList.sourceBoundsWithOrigin();
143*c8dee2aaSAndroid Build Coastguard Worker if (this->internalQuickReject(bounds, paint)) {
144*c8dee2aaSAndroid Build Coastguard Worker return;
145*c8dee2aaSAndroid Build Coastguard Worker }
146*c8dee2aaSAndroid Build Coastguard Worker auto layer = this->aboutToDraw(paint, &bounds);
147*c8dee2aaSAndroid Build Coastguard Worker if (layer) {
148*c8dee2aaSAndroid Build Coastguard Worker if (glyphRunList.hasRSXForm()) {
149*c8dee2aaSAndroid Build Coastguard Worker this->SkCanvas::onDrawGlyphRunList(glyphRunList, layer->paint());
150*c8dee2aaSAndroid Build Coastguard Worker } else {
151*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkData> slugBytes;
152*c8dee2aaSAndroid Build Coastguard Worker std::vector<uint8_t> glyphBytes;
153*c8dee2aaSAndroid Build Coastguard Worker {
154*c8dee2aaSAndroid Build Coastguard Worker auto analysisCanvas = fStrikeServer.makeAnalysisCanvas(
155*c8dee2aaSAndroid Build Coastguard Worker this->topDevice()->width(),
156*c8dee2aaSAndroid Build Coastguard Worker this->topDevice()->height(),
157*c8dee2aaSAndroid Build Coastguard Worker this->fProps,
158*c8dee2aaSAndroid Build Coastguard Worker this->topDevice()->imageInfo().refColorSpace(),
159*c8dee2aaSAndroid Build Coastguard Worker // TODO: Where should we get this value from?
160*c8dee2aaSAndroid Build Coastguard Worker /*DFTSupport=*/ true);
161*c8dee2aaSAndroid Build Coastguard Worker
162*c8dee2aaSAndroid Build Coastguard Worker // TODO: Move the analysis canvas processing up to the via to handle a whole
163*c8dee2aaSAndroid Build Coastguard Worker // document at a time. This is not the correct way to handle the CTM; it doesn't
164*c8dee2aaSAndroid Build Coastguard Worker // work for layers.
165*c8dee2aaSAndroid Build Coastguard Worker analysisCanvas->setMatrix(this->getLocalToDevice());
166*c8dee2aaSAndroid Build Coastguard Worker auto slug = analysisCanvas->onConvertGlyphRunListToSlug(glyphRunList,
167*c8dee2aaSAndroid Build Coastguard Worker layer->paint());
168*c8dee2aaSAndroid Build Coastguard Worker if (slug != nullptr) {
169*c8dee2aaSAndroid Build Coastguard Worker slugBytes = slug->serialize();
170*c8dee2aaSAndroid Build Coastguard Worker }
171*c8dee2aaSAndroid Build Coastguard Worker fStrikeServer.writeStrikeData(&glyphBytes);
172*c8dee2aaSAndroid Build Coastguard Worker }
173*c8dee2aaSAndroid Build Coastguard Worker {
174*c8dee2aaSAndroid Build Coastguard Worker if (!glyphBytes.empty()) {
175*c8dee2aaSAndroid Build Coastguard Worker fStrikeClient.readStrikeData(glyphBytes.data(), glyphBytes.size());
176*c8dee2aaSAndroid Build Coastguard Worker }
177*c8dee2aaSAndroid Build Coastguard Worker if (slugBytes != nullptr) {
178*c8dee2aaSAndroid Build Coastguard Worker auto slug = sktext::gpu::Slug::Deserialize(
179*c8dee2aaSAndroid Build Coastguard Worker slugBytes->data(), slugBytes->size(), &fStrikeClient);
180*c8dee2aaSAndroid Build Coastguard Worker this->drawSlug(slug.get(), layer->paint());
181*c8dee2aaSAndroid Build Coastguard Worker }
182*c8dee2aaSAndroid Build Coastguard Worker }
183*c8dee2aaSAndroid Build Coastguard Worker }
184*c8dee2aaSAndroid Build Coastguard Worker }
185*c8dee2aaSAndroid Build Coastguard Worker }
186*c8dee2aaSAndroid Build Coastguard Worker
187*c8dee2aaSAndroid Build Coastguard Worker } // namespace skiatest
188