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