| // Copyright 2019 Google LLC. | |
| // Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. | |
| #include "src/core/SkTextBlobTrace.h" | |
| #include "include/core/SkTextBlob.h" | |
| #include "src/core/SkFontPriv.h" | |
| #include "src/core/SkPtrRecorder.h" | |
| #include "src/core/SkReadBuffer.h" | |
| #include "src/core/SkTextBlobPriv.h" | |
| #include "src/core/SkWriteBuffer.h" | |
| std::vector<SkTextBlobTrace::Record> SkTextBlobTrace::CreateBlobTrace(SkStream* stream) { | |
| std::vector<SkTextBlobTrace::Record> trace; | |
| uint32_t typefaceCount; | |
| if (!stream->readU32(&typefaceCount)) { | |
| return trace; | |
| } | |
| std::vector<sk_sp<SkTypeface>> typefaceArray; | |
| for (uint32_t i = 0; i < typefaceCount; i++) { | |
| typefaceArray.push_back(SkTypeface::MakeDeserialize(stream)); | |
| } | |
| uint32_t restOfFile; | |
| if (!stream->readU32(&restOfFile)) { | |
| return trace; | |
| } | |
| sk_sp<SkData> data = SkData::MakeFromStream(stream, restOfFile); | |
| SkReadBuffer readBuffer{data->data(), data->size()}; | |
| readBuffer.setTypefaceArray(typefaceArray.data(), typefaceArray.size()); | |
| while (!readBuffer.eof()) { | |
| SkTextBlobTrace::Record record; | |
| record.origUniqueID = readBuffer.readUInt(); | |
| readBuffer.readPaint(&record.paint, nullptr); | |
| readBuffer.readPoint(&record.offset); | |
| record.blob = SkTextBlobPriv::MakeFromBuffer(readBuffer); | |
| trace.push_back(std::move(record)); | |
| } | |
| return trace; | |
| } | |
| void SkTextBlobTrace::DumpTrace(const std::vector<SkTextBlobTrace::Record>& trace) { | |
| for (const SkTextBlobTrace::Record& record : trace) { | |
| const SkTextBlob* blob = record.blob.get(); | |
| const SkPaint& p = record.paint; | |
| bool weirdPaint = p.getStyle() != SkPaint::kFill_Style | |
| || p.getMaskFilter() != nullptr | |
| || p.getPathEffect() != nullptr; | |
| SkDebugf("Blob %d ( %g %g ) %d\n ", | |
| blob->uniqueID(), record.offset.x(), record.offset.y(), weirdPaint); | |
| SkTextBlobRunIterator iter(blob); | |
| int runNumber = 0; | |
| while (!iter.done()) { | |
| SkDebugf("Run %d\n ", runNumber); | |
| SkFont font = iter.font(); | |
| SkDebugf("Font %d %g %g %g %d %d %d\n ", | |
| font.getTypefaceOrDefault()->uniqueID(), | |
| font.getSize(), | |
| font.getScaleX(), | |
| font.getSkewX(), | |
| SkFontPriv::Flags(font), | |
| (int)font.getEdging(), | |
| (int)font.getHinting()); | |
| uint32_t glyphCount = iter.glyphCount(); | |
| const uint16_t* glyphs = iter.glyphs(); | |
| for (uint32_t i = 0; i < glyphCount; i++) { | |
| SkDebugf("%02X ", glyphs[i]); | |
| } | |
| SkDebugf("\n"); | |
| runNumber += 1; | |
| iter.next(); | |
| } | |
| } | |
| } | |
| SkTextBlobTrace::Capture::Capture() : fTypefaceSet(new SkRefCntSet) { | |
| fWriteBuffer.setTypefaceRecorder(fTypefaceSet); | |
| } | |
| SkTextBlobTrace::Capture::~Capture() = default; | |
| void SkTextBlobTrace::Capture::capture(const SkGlyphRunList& glyphRunList, const SkPaint& paint) { | |
| const SkTextBlob* blob = glyphRunList.blob(); | |
| if (blob != nullptr) { | |
| fWriteBuffer.writeUInt(blob->uniqueID()); | |
| fWriteBuffer.writePaint(paint); | |
| fWriteBuffer.writePoint(glyphRunList.origin()); | |
| SkTextBlobPriv::Flatten(*blob, fWriteBuffer); | |
| fBlobCount++; | |
| } | |
| } | |
| void SkTextBlobTrace::Capture::dump(SkWStream* dst) const { | |
| SkTLazy<SkFILEWStream> fileStream; | |
| if (!dst) { | |
| uint32_t id = SkChecksum::Mix(reinterpret_cast<uintptr_t>(this)); | |
| SkString f = SkStringPrintf("diff-canvas-%08x-%04zu.trace", id, fBlobCount); | |
| dst = fileStream.init(f.c_str()); | |
| if (!fileStream->isValid()) { | |
| SkDebugf("Error opening '%s'.\n", f.c_str()); | |
| return; | |
| } | |
| SkDebugf("Saving trace to '%s'.\n", f.c_str()); | |
| } | |
| SkASSERT(dst); | |
| int count = fTypefaceSet->count(); | |
| dst->write32(count); | |
| SkPtrSet::Iter iter(*fTypefaceSet); | |
| while (void* ptr = iter.next()) { | |
| ((const SkTypeface*)ptr)->serialize(dst, SkTypeface::SerializeBehavior::kDoIncludeData); | |
| } | |
| dst->write32(fWriteBuffer.bytesWritten()); | |
| fWriteBuffer.writeToStream(dst); | |
| } |