// 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::CreateBlobTrace(SkStream* stream) { std::vector trace; uint32_t typefaceCount; if (!stream->readU32(&typefaceCount)) { return trace; } std::vector> 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 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& 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 fileStream; if (!dst) { uint32_t id = SkChecksum::Mix(reinterpret_cast(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); }