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