xref: /aosp_15_r20/external/skia/tools/text/SkTextBlobTrace.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1 // Copyright 2019 Google LLC.
2 // Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.
3 
4 #include "tools/text/SkTextBlobTrace.h"
5 
6 #include "include/core/SkData.h"
7 #include "include/core/SkFont.h"
8 #include "include/core/SkFontMgr.h"
9 #include "include/core/SkStream.h"
10 #include "include/core/SkString.h"
11 #include "include/core/SkTextBlob.h"
12 #include "include/core/SkTypeface.h"
13 #include "include/private/base/SkDebug.h"
14 #include "src/base/SkTLazy.h"
15 #include "src/core/SkChecksum.h"
16 #include "src/core/SkFontPriv.h"
17 #include "src/core/SkPtrRecorder.h"
18 #include "src/core/SkReadBuffer.h"
19 #include "src/core/SkTextBlobPriv.h"
20 #include "src/core/SkWriteBuffer.h"
21 #include "src/text/GlyphRun.h"
22 
23 #include <utility>
24 
CreateBlobTrace(SkStream * stream,sk_sp<SkFontMgr> lastResortMgr)25 std::vector<SkTextBlobTrace::Record> SkTextBlobTrace::CreateBlobTrace(
26         SkStream* stream, sk_sp<SkFontMgr> lastResortMgr) {
27     std::vector<SkTextBlobTrace::Record> trace;
28 
29     uint32_t typefaceCount;
30     if (!stream->readU32(&typefaceCount)) {
31         return trace;
32     }
33 
34     std::vector<sk_sp<SkTypeface>> typefaceArray;
35     for (uint32_t i = 0; i < typefaceCount; i++) {
36         typefaceArray.push_back(SkTypeface::MakeDeserialize(stream, lastResortMgr));
37     }
38 
39     uint32_t restOfFile;
40     if (!stream->readU32(&restOfFile)) {
41         return trace;
42     }
43     sk_sp<SkData> data = SkData::MakeFromStream(stream, restOfFile);
44     SkReadBuffer readBuffer{data->data(), data->size()};
45     readBuffer.setTypefaceArray(typefaceArray.data(), typefaceArray.size());
46 
47     while (!readBuffer.eof()) {
48         SkTextBlobTrace::Record record;
49         record.origUniqueID = readBuffer.readUInt();
50         record.paint = readBuffer.readPaint();
51         readBuffer.readPoint(&record.offset);
52         record.blob = SkTextBlobPriv::MakeFromBuffer(readBuffer);
53         trace.push_back(std::move(record));
54     }
55     return trace;
56 }
57 
DumpTrace(const std::vector<SkTextBlobTrace::Record> & trace)58 void SkTextBlobTrace::DumpTrace(const std::vector<SkTextBlobTrace::Record>& trace) {
59     for (const SkTextBlobTrace::Record& record : trace) {
60         const SkTextBlob* blob = record.blob.get();
61         const SkPaint& p = record.paint;
62         bool weirdPaint = p.getStyle() != SkPaint::kFill_Style
63         || p.getMaskFilter() != nullptr
64         || p.getPathEffect() != nullptr;
65 
66         SkDebugf("Blob %u ( %g %g ) %d\n  ",
67                 blob->uniqueID(), record.offset.x(), record.offset.y(), weirdPaint);
68         SkTextBlobRunIterator iter(blob);
69         int runNumber = 0;
70         while (!iter.done()) {
71             SkDebugf("Run %d\n    ", runNumber);
72             SkFont font = iter.font();
73             SkDebugf("Font %u %g %g %g %d %d %d\n    ",
74                     font.getTypeface()->uniqueID(),
75                     font.getSize(),
76                     font.getScaleX(),
77                     font.getSkewX(),
78                     SkFontPriv::Flags(font),
79                     (int)font.getEdging(),
80                     (int)font.getHinting());
81             uint32_t glyphCount = iter.glyphCount();
82             const uint16_t* glyphs = iter.glyphs();
83             for (uint32_t i = 0; i < glyphCount; i++) {
84                 SkDebugf("%02X ", glyphs[i]);
85             }
86             SkDebugf("\n");
87             runNumber += 1;
88             iter.next();
89         }
90     }
91 }
92 
Capture()93 SkTextBlobTrace::Capture::Capture() : fTypefaceSet(new SkRefCntSet), fWriteBuffer({}) {
94     fWriteBuffer.setTypefaceRecorder(fTypefaceSet);
95 }
96 
97 SkTextBlobTrace::Capture::~Capture() = default;
98 
capture(const sktext::GlyphRunList & glyphRunList,const SkPaint & paint)99 void SkTextBlobTrace::Capture::capture(
100         const sktext::GlyphRunList& glyphRunList, const SkPaint& paint) {
101     const SkTextBlob* blob = glyphRunList.blob();
102     if (blob != nullptr) {
103         fWriteBuffer.writeUInt(blob->uniqueID());
104         fWriteBuffer.writePaint(paint);
105         fWriteBuffer.writePoint(glyphRunList.origin());
106         SkTextBlobPriv::Flatten(*blob, fWriteBuffer);
107         fBlobCount++;
108     }
109 }
110 
dump(SkWStream * dst) const111 void SkTextBlobTrace::Capture::dump(SkWStream* dst) const {
112     SkTLazy<SkFILEWStream> fileStream;
113     if (!dst) {
114         uint32_t id = SkChecksum::Mix(reinterpret_cast<uintptr_t>(this));
115         SkString f = SkStringPrintf("diff-canvas-%08x-%04zu.trace", id, fBlobCount);
116         dst = fileStream.init(f.c_str());
117         if (!fileStream->isValid()) {
118             SkDebugf("Error opening '%s'.\n", f.c_str());
119             return;
120         }
121         SkDebugf("Saving trace to '%s'.\n", f.c_str());
122     }
123     SkASSERT(dst);
124     int count = fTypefaceSet->count();
125     dst->write32(count);
126     SkPtrSet::Iter iter(*fTypefaceSet);
127     while (void* ptr = iter.next()) {
128         ((const SkTypeface*)ptr)->serialize(dst, SkTypeface::SerializeBehavior::kDoIncludeData);
129     }
130     dst->write32(fWriteBuffer.bytesWritten());
131     fWriteBuffer.writeToStream(dst);
132 }
133