1cb93a386Sopenharmony_ci/*
2cb93a386Sopenharmony_ci * Copyright 2019 Google Inc.
3cb93a386Sopenharmony_ci *
4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be
5cb93a386Sopenharmony_ci * found in the LICENSE file.
6cb93a386Sopenharmony_ci */
7cb93a386Sopenharmony_ci
8cb93a386Sopenharmony_ci#include "src/utils/SkShaperJSONWriter.h"
9cb93a386Sopenharmony_ci
10cb93a386Sopenharmony_ci#include <algorithm>
11cb93a386Sopenharmony_ci#include <limits>
12cb93a386Sopenharmony_ci#include <string>
13cb93a386Sopenharmony_ci
14cb93a386Sopenharmony_ci#include "src/utils/SkJSONWriter.h"
15cb93a386Sopenharmony_ci#include "src/utils/SkUTF.h"
16cb93a386Sopenharmony_ci
17cb93a386Sopenharmony_ciSkShaperJSONWriter::SkShaperJSONWriter(SkJSONWriter* JSONWriter, const char* utf8, size_t size)
18cb93a386Sopenharmony_ci        : fJSONWriter{JSONWriter}
19cb93a386Sopenharmony_ci        , fUTF8{utf8, size} {}
20cb93a386Sopenharmony_ci
21cb93a386Sopenharmony_civoid SkShaperJSONWriter::beginLine() { }
22cb93a386Sopenharmony_ci
23cb93a386Sopenharmony_civoid SkShaperJSONWriter::runInfo(const SkShaper::RunHandler::RunInfo& info) { }
24cb93a386Sopenharmony_ci
25cb93a386Sopenharmony_civoid SkShaperJSONWriter::commitRunInfo() { }
26cb93a386Sopenharmony_ci
27cb93a386Sopenharmony_ciSkShaper::RunHandler::Buffer
28cb93a386Sopenharmony_ciSkShaperJSONWriter::runBuffer(const SkShaper::RunHandler::RunInfo& info) {
29cb93a386Sopenharmony_ci    fGlyphs.resize(info.glyphCount);
30cb93a386Sopenharmony_ci    fPositions.resize(info.glyphCount);
31cb93a386Sopenharmony_ci    fClusters.resize(info.glyphCount);
32cb93a386Sopenharmony_ci    return {fGlyphs.data(), fPositions.data(), nullptr, fClusters.data(), {0, 0}};
33cb93a386Sopenharmony_ci}
34cb93a386Sopenharmony_ci
35cb93a386Sopenharmony_cistatic bool is_one_to_one(const char utf8[], size_t utf8Begin, size_t utf8End,
36cb93a386Sopenharmony_ci        std::vector<uint32_t>& clusters) {
37cb93a386Sopenharmony_ci    size_t lastUtf8Index = utf8End;
38cb93a386Sopenharmony_ci
39cb93a386Sopenharmony_ci    auto checkCluster = [&](size_t clusterIndex) {
40cb93a386Sopenharmony_ci        if (clusters[clusterIndex] >= lastUtf8Index) {
41cb93a386Sopenharmony_ci            return false;
42cb93a386Sopenharmony_ci        }
43cb93a386Sopenharmony_ci        size_t utf8ClusterSize = lastUtf8Index - clusters[clusterIndex];
44cb93a386Sopenharmony_ci        if (SkUTF::CountUTF8(&utf8[clusters[clusterIndex]], utf8ClusterSize) != 1) {
45cb93a386Sopenharmony_ci            return false;
46cb93a386Sopenharmony_ci        }
47cb93a386Sopenharmony_ci        lastUtf8Index = clusters[clusterIndex];
48cb93a386Sopenharmony_ci        return true;
49cb93a386Sopenharmony_ci    };
50cb93a386Sopenharmony_ci
51cb93a386Sopenharmony_ci    if (clusters.front() <= clusters.back()) {
52cb93a386Sopenharmony_ci        // left-to-right clusters
53cb93a386Sopenharmony_ci        size_t clusterCursor = clusters.size();
54cb93a386Sopenharmony_ci        while (clusterCursor > 0) {
55cb93a386Sopenharmony_ci            if (!checkCluster(--clusterCursor)) { return false; }
56cb93a386Sopenharmony_ci        }
57cb93a386Sopenharmony_ci    } else {
58cb93a386Sopenharmony_ci        // right-to-left clusters
59cb93a386Sopenharmony_ci        size_t clusterCursor = 0;
60cb93a386Sopenharmony_ci        while (clusterCursor < clusters.size()) {
61cb93a386Sopenharmony_ci            if (!checkCluster(clusterCursor++)) { return false; }
62cb93a386Sopenharmony_ci        }
63cb93a386Sopenharmony_ci    }
64cb93a386Sopenharmony_ci
65cb93a386Sopenharmony_ci    return true;
66cb93a386Sopenharmony_ci}
67cb93a386Sopenharmony_ci
68cb93a386Sopenharmony_civoid SkShaperJSONWriter::commitRunBuffer(const SkShaper::RunHandler::RunInfo& info) {
69cb93a386Sopenharmony_ci    fJSONWriter->beginObject("run", true);
70cb93a386Sopenharmony_ci
71cb93a386Sopenharmony_ci    // Font name
72cb93a386Sopenharmony_ci    SkString fontName;
73cb93a386Sopenharmony_ci    info.fFont.getTypeface()->getFamilyName(&fontName);
74cb93a386Sopenharmony_ci    fJSONWriter->appendString("font name", fontName.c_str());
75cb93a386Sopenharmony_ci
76cb93a386Sopenharmony_ci    // Font size
77cb93a386Sopenharmony_ci    fJSONWriter->appendFloat("font size", info.fFont.getSize());
78cb93a386Sopenharmony_ci
79cb93a386Sopenharmony_ci    if (info.fBidiLevel > 0) {
80cb93a386Sopenharmony_ci        std::string bidiType = info.fBidiLevel % 2 == 0 ? "left-to-right" : "right-to-left";
81cb93a386Sopenharmony_ci        std::string bidiOutput = bidiType + " lvl " + std::to_string(info.fBidiLevel);
82cb93a386Sopenharmony_ci        fJSONWriter->appendString("BiDi", bidiOutput.c_str());
83cb93a386Sopenharmony_ci    }
84cb93a386Sopenharmony_ci
85cb93a386Sopenharmony_ci    if (is_one_to_one(fUTF8.c_str(), info.utf8Range.begin(), info.utf8Range.end(), fClusters)) {
86cb93a386Sopenharmony_ci        std::string utf8{&fUTF8[info.utf8Range.begin()], info.utf8Range.size()};
87cb93a386Sopenharmony_ci        fJSONWriter->appendString("UTF8", utf8.c_str());
88cb93a386Sopenharmony_ci
89cb93a386Sopenharmony_ci        fJSONWriter->beginArray("glyphs", false);
90cb93a386Sopenharmony_ci        for (auto glyphID : fGlyphs) {
91cb93a386Sopenharmony_ci            fJSONWriter->appendU32(glyphID);
92cb93a386Sopenharmony_ci        }
93cb93a386Sopenharmony_ci        fJSONWriter->endArray();
94cb93a386Sopenharmony_ci
95cb93a386Sopenharmony_ci        fJSONWriter->beginArray("clusters", false);
96cb93a386Sopenharmony_ci        for (auto cluster : fClusters) {
97cb93a386Sopenharmony_ci            fJSONWriter->appendU32(cluster);
98cb93a386Sopenharmony_ci        }
99cb93a386Sopenharmony_ci        fJSONWriter->endArray();
100cb93a386Sopenharmony_ci    } else {
101cb93a386Sopenharmony_ci        VisualizeClusters(fUTF8.c_str(),
102cb93a386Sopenharmony_ci                          info.utf8Range.begin(), info.utf8Range.end(),
103cb93a386Sopenharmony_ci                          SkMakeSpan(fGlyphs),
104cb93a386Sopenharmony_ci                          SkMakeSpan(fClusters),
105cb93a386Sopenharmony_ci                          [this](size_t codePointCount, SkSpan<const char> utf1to1,
106cb93a386Sopenharmony_ci                                 SkSpan<const SkGlyphID> glyph1to1) {
107cb93a386Sopenharmony_ci                              this->displayMToN(codePointCount, utf1to1, glyph1to1);
108cb93a386Sopenharmony_ci                          });
109cb93a386Sopenharmony_ci    }
110cb93a386Sopenharmony_ci
111cb93a386Sopenharmony_ci    if (info.glyphCount > 1) {
112cb93a386Sopenharmony_ci        fJSONWriter->beginArray("horizontal positions", false);
113cb93a386Sopenharmony_ci        for (auto position : fPositions) {
114cb93a386Sopenharmony_ci            fJSONWriter->appendFloat(position.x());
115cb93a386Sopenharmony_ci        }
116cb93a386Sopenharmony_ci        fJSONWriter->endArray();
117cb93a386Sopenharmony_ci    }
118cb93a386Sopenharmony_ci
119cb93a386Sopenharmony_ci    fJSONWriter->beginArray("advances", false);
120cb93a386Sopenharmony_ci    for (size_t i = 1; i < info.glyphCount; i++) {
121cb93a386Sopenharmony_ci        fJSONWriter->appendFloat(fPositions[i].fX - fPositions[i-1].fX);
122cb93a386Sopenharmony_ci    }
123cb93a386Sopenharmony_ci    SkPoint lastAdvance = info.fAdvance - (fPositions.back() - fPositions.front());
124cb93a386Sopenharmony_ci    fJSONWriter->appendFloat(lastAdvance.fX);
125cb93a386Sopenharmony_ci    fJSONWriter->endArray();
126cb93a386Sopenharmony_ci
127cb93a386Sopenharmony_ci    fJSONWriter->endObject();
128cb93a386Sopenharmony_ci}
129cb93a386Sopenharmony_ci
130cb93a386Sopenharmony_civoid SkShaperJSONWriter::BreakupClusters(size_t utf8Begin, size_t utf8End,
131cb93a386Sopenharmony_ci                                         SkSpan<const uint32_t> clusters,
132cb93a386Sopenharmony_ci                                         const BreakupCluastersCallback& processMToN) {
133cb93a386Sopenharmony_ci
134cb93a386Sopenharmony_ci    if (clusters.front() <= clusters.back()) {
135cb93a386Sopenharmony_ci        // Handle left-to-right text direction
136cb93a386Sopenharmony_ci        size_t glyphStartIndex = 0;
137cb93a386Sopenharmony_ci        for (size_t glyphEndIndex = 0; glyphEndIndex < clusters.size(); glyphEndIndex++) {
138cb93a386Sopenharmony_ci
139cb93a386Sopenharmony_ci            if (clusters[glyphStartIndex] == clusters[glyphEndIndex]) { continue; }
140cb93a386Sopenharmony_ci
141cb93a386Sopenharmony_ci            processMToN(glyphStartIndex, glyphEndIndex,
142cb93a386Sopenharmony_ci                        clusters[glyphStartIndex], clusters[glyphEndIndex]);
143cb93a386Sopenharmony_ci
144cb93a386Sopenharmony_ci            glyphStartIndex = glyphEndIndex;
145cb93a386Sopenharmony_ci        }
146cb93a386Sopenharmony_ci
147cb93a386Sopenharmony_ci        processMToN(glyphStartIndex, clusters.size(), clusters[glyphStartIndex], utf8End);
148cb93a386Sopenharmony_ci
149cb93a386Sopenharmony_ci    } else {
150cb93a386Sopenharmony_ci        // Handle right-to-left text direction.
151cb93a386Sopenharmony_ci        SkASSERT(clusters.size() >= 2);
152cb93a386Sopenharmony_ci        size_t glyphStartIndex = 0;
153cb93a386Sopenharmony_ci        uint32_t utf8EndIndex = utf8End;
154cb93a386Sopenharmony_ci        for (size_t glyphEndIndex = 0; glyphEndIndex < clusters.size(); glyphEndIndex++) {
155cb93a386Sopenharmony_ci
156cb93a386Sopenharmony_ci            if (clusters[glyphStartIndex] == clusters[glyphEndIndex]) { continue; }
157cb93a386Sopenharmony_ci
158cb93a386Sopenharmony_ci            processMToN(glyphStartIndex, glyphEndIndex,
159cb93a386Sopenharmony_ci                        clusters[glyphStartIndex], utf8EndIndex);
160cb93a386Sopenharmony_ci
161cb93a386Sopenharmony_ci            utf8EndIndex = clusters[glyphStartIndex];
162cb93a386Sopenharmony_ci            glyphStartIndex = glyphEndIndex;
163cb93a386Sopenharmony_ci        }
164cb93a386Sopenharmony_ci        processMToN(glyphStartIndex, clusters.size(), utf8Begin, clusters[glyphStartIndex-1]);
165cb93a386Sopenharmony_ci    }
166cb93a386Sopenharmony_ci}
167cb93a386Sopenharmony_ci
168cb93a386Sopenharmony_civoid SkShaperJSONWriter::VisualizeClusters(const char* utf8, size_t utf8Begin, size_t utf8End,
169cb93a386Sopenharmony_ci                                           SkSpan<const SkGlyphID> glyphIDs,
170cb93a386Sopenharmony_ci                                           SkSpan<const uint32_t> clusters,
171cb93a386Sopenharmony_ci                                           const VisualizeClustersCallback& processMToN) {
172cb93a386Sopenharmony_ci
173cb93a386Sopenharmony_ci    size_t glyphRangeStart, glyphRangeEnd;
174cb93a386Sopenharmony_ci    uint32_t utf8RangeStart, utf8RangeEnd;
175cb93a386Sopenharmony_ci
176cb93a386Sopenharmony_ci    auto resetRanges = [&]() {
177cb93a386Sopenharmony_ci        glyphRangeStart = std::numeric_limits<size_t>::max();
178cb93a386Sopenharmony_ci        glyphRangeEnd   = 0;
179cb93a386Sopenharmony_ci        utf8RangeStart  = std::numeric_limits<uint32_t>::max();
180cb93a386Sopenharmony_ci        utf8RangeEnd    = 0;
181cb93a386Sopenharmony_ci    };
182cb93a386Sopenharmony_ci
183cb93a386Sopenharmony_ci    auto checkRangesAndProcess = [&]() {
184cb93a386Sopenharmony_ci        if (glyphRangeStart < glyphRangeEnd) {
185cb93a386Sopenharmony_ci            size_t glyphRangeCount = glyphRangeEnd - glyphRangeStart;
186cb93a386Sopenharmony_ci            SkSpan<const char> utf8Span{&utf8[utf8RangeStart], utf8RangeEnd - utf8RangeStart};
187cb93a386Sopenharmony_ci            SkSpan<const SkGlyphID> glyphSpan{&glyphIDs[glyphRangeStart], glyphRangeCount};
188cb93a386Sopenharmony_ci
189cb93a386Sopenharmony_ci            // Glyph count is the same as codepoint count for 1:1.
190cb93a386Sopenharmony_ci            processMToN(glyphRangeCount, utf8Span, glyphSpan);
191cb93a386Sopenharmony_ci        }
192cb93a386Sopenharmony_ci        resetRanges();
193cb93a386Sopenharmony_ci    };
194cb93a386Sopenharmony_ci
195cb93a386Sopenharmony_ci    auto gatherRuns = [&](size_t glyphStartIndex, size_t glyphEndIndex,
196cb93a386Sopenharmony_ci                          uint32_t utf8StartIndex, uint32_t utf8EndIndex) {
197cb93a386Sopenharmony_ci        int possibleCount = SkUTF::CountUTF8(&utf8[utf8StartIndex], utf8EndIndex - utf8StartIndex);
198cb93a386Sopenharmony_ci        if (possibleCount == -1) { return; }
199cb93a386Sopenharmony_ci        size_t codePointCount = SkTo<size_t>(possibleCount);
200cb93a386Sopenharmony_ci        if (codePointCount == 1 && glyphEndIndex - glyphStartIndex == 1) {
201cb93a386Sopenharmony_ci            glyphRangeStart = std::min(glyphRangeStart, glyphStartIndex);
202cb93a386Sopenharmony_ci            glyphRangeEnd   = std::max(glyphRangeEnd,   glyphEndIndex  );
203cb93a386Sopenharmony_ci            utf8RangeStart  = std::min(utf8RangeStart,  utf8StartIndex );
204cb93a386Sopenharmony_ci            utf8RangeEnd    = std::max(utf8RangeEnd,    utf8EndIndex   );
205cb93a386Sopenharmony_ci        } else {
206cb93a386Sopenharmony_ci            checkRangesAndProcess();
207cb93a386Sopenharmony_ci
208cb93a386Sopenharmony_ci            SkSpan<const char> utf8Span{&utf8[utf8StartIndex], utf8EndIndex - utf8StartIndex};
209cb93a386Sopenharmony_ci            SkSpan<const SkGlyphID> glyphSpan{&glyphIDs[glyphStartIndex],
210cb93a386Sopenharmony_ci                                              glyphEndIndex - glyphStartIndex};
211cb93a386Sopenharmony_ci
212cb93a386Sopenharmony_ci            processMToN(codePointCount, utf8Span, glyphSpan);
213cb93a386Sopenharmony_ci        }
214cb93a386Sopenharmony_ci    };
215cb93a386Sopenharmony_ci
216cb93a386Sopenharmony_ci    resetRanges();
217cb93a386Sopenharmony_ci    BreakupClusters(utf8Begin, utf8End, clusters, gatherRuns);
218cb93a386Sopenharmony_ci    checkRangesAndProcess();
219cb93a386Sopenharmony_ci}
220cb93a386Sopenharmony_ci
221cb93a386Sopenharmony_civoid SkShaperJSONWriter::displayMToN(size_t codePointCount,
222cb93a386Sopenharmony_ci                                     SkSpan<const char> utf8,
223cb93a386Sopenharmony_ci                                     SkSpan<const SkGlyphID> glyphIDs) {
224cb93a386Sopenharmony_ci    std::string nString = std::to_string(codePointCount);
225cb93a386Sopenharmony_ci    std::string mString = std::to_string(glyphIDs.size());
226cb93a386Sopenharmony_ci    std::string clusterName = "cluster " + nString + " to " + mString;
227cb93a386Sopenharmony_ci    fJSONWriter->beginObject(clusterName.c_str(), true);
228cb93a386Sopenharmony_ci    std::string utf8String{utf8.data(), utf8.size()};
229cb93a386Sopenharmony_ci    fJSONWriter->appendString("UTF", utf8String.c_str());
230cb93a386Sopenharmony_ci    fJSONWriter->beginArray("glyphsIDs", false);
231cb93a386Sopenharmony_ci    for (auto glyphID : glyphIDs) {
232cb93a386Sopenharmony_ci        fJSONWriter->appendU32(glyphID);
233cb93a386Sopenharmony_ci    }
234cb93a386Sopenharmony_ci    fJSONWriter->endArray();
235cb93a386Sopenharmony_ci    fJSONWriter->endObject();
236cb93a386Sopenharmony_ci}
237