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         readBuffer.readPaint(&record.paint, nullptr);
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                     font.getEdging(),
67                     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