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