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 13std::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 45void 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 80SkTextBlobTrace::Capture::Capture() : fTypefaceSet(new SkRefCntSet) { 81 fWriteBuffer.setTypefaceRecorder(fTypefaceSet); 82} 83 84SkTextBlobTrace::Capture::~Capture() = default; 85 86void 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 97void 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