1 /*
2 * Copyright 2019 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8 #include "include/core/SkCanvas.h"
9 #include "include/core/SkColor.h"
10 #include "include/core/SkFontMgr.h"
11 #include "include/core/SkStream.h"
12 #include "include/core/SkSurface.h"
13 #include "include/encode/SkPngEncoder.h"
14 #include "include/private/chromium/SkChromeRemoteGlyphCache.h"
15 #include "src/core/SkScalerContext.h"
16 #include "tools/text/SkTextBlobTrace.h"
17
18 #include <iostream>
19 #include <string>
20 #include <unordered_map>
21 #include <vector>
22
main(int argc,char ** argv)23 int main(int argc, char** argv) {
24 std::unordered_map<uint64_t, uint32_t> counts;
25 size_t total = 0;
26
27 for (int i = 1; i < argc; i++) {
28 const char* filename = argv[i];
29
30 SkFILEStream in{filename};
31 std::vector<SkTextBlobTrace::Record> trace = SkTextBlobTrace::CreateBlobTrace(&in, nullptr);
32 for (const SkTextBlobTrace::Record& record : trace) {
33 total++;
34 const SkPaint paint = record.paint;
35 bool fastByPass = paint.getStyle() == SkPaint::kFill_Style
36 && paint.getPathEffect() == nullptr
37 && paint.getMaskFilter() == nullptr;
38 if (fastByPass) {
39 uint64_t blobID = record.origUniqueID;
40 SkPoint offset = record.offset;
41 SkColor c = SkMaskGamma::CanonicalColor(paint.getColor());
42 uint32_t colorBits =
43 (SkColorGetR(c) >> 5u) << 6u
44 | (SkColorGetG(c) >> 5u) << 3u
45 | SkColorGetB(c) >> 5u;
46
47 SkFixed fx = (SkScalarToFixed(offset.x()) >> 13) & 7;
48 SkFixed fy = (SkScalarToFixed(offset.y()) >> 13) & 7;
49 uint32_t posBits = (fx << 3 | fy) << 12;
50
51 uint64_t blobKey = blobID << 32u | posBits | colorBits;
52 auto lookup = counts.find(blobKey);
53 if (lookup == counts.end()) {
54 bool ok;
55 std::tie(lookup, ok) = counts.insert({blobKey, 0});
56 SkASSERT(ok);
57 }
58 lookup->second += 1;
59 std::cout << std::hex << blobKey << "\n";
60 }
61 }
62 std::cerr << "trace: " << filename
63 << " unique: " << counts.size()
64 << " all: " << total
65 << " ratio: " << (float)total/counts.size() << "\n";
66
67 SkRect bounds = {0, 0, 0, 0};
68 for (const SkTextBlobTrace::Record& record : trace) {
69 bounds.join(record.blob->bounds().makeOffset(record.offset.x(), record.offset.y()));
70 }
71 SkIRect iBounds = bounds.roundOut();
72 if (iBounds.size().isEmpty()) {
73 continue;
74 }
75 static constexpr SkColor kBackground = SK_ColorWHITE;
76 sk_sp<SkSurface> surf = SkSurfaces::Raster(
77 SkImageInfo::MakeN32Premul(iBounds.width() + 16, iBounds.height() + 16));
78 SkCanvas* canvas = surf->getCanvas();
79 canvas->translate(8.0f - iBounds.x(), 8.0f - iBounds.y());
80 canvas->clear(kBackground);
81
82 for (const SkTextBlobTrace::Record& record : trace) {
83 canvas->drawTextBlob(
84 record.blob.get(), record.offset.x(), record.offset.y(), record.paint);
85 }
86
87 sk_sp<SkImage> img(surf->makeImageSnapshot());
88 if (img) {
89 sk_sp<SkData> png = SkPngEncoder::Encode(nullptr, img.get(), {});
90 if (png) {
91 SkString path = SkStringPrintf("text_blob_trace_%04d.png", i);
92 SkFILEWStream(path.c_str()).write(png->data(), png->size());
93 }
94 }
95 }
96 return 0;
97 }
98