1ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com/* 2ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Copyright 2006 The Android Open Source Project 3ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * 4ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Use of this source code is governed by a BSD-style license that can be 5ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * found in the LICENSE file. 6ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com */ 7ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com 88a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkTextBox.h" 98a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkUtils.h" 108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comstatic inline int is_ws(int c) 128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com{ 138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return !((c - 1) >> 5); 148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 160d50bc14901ee87552224ee4f1ec84f2f1db7320bungeman@google.comstatic size_t linebreak(const char text[], const char stop[], 170d50bc14901ee87552224ee4f1ec84f2f1db7320bungeman@google.com const SkPaint& paint, SkScalar margin, 182880df2609eba09b555ca37be04b6ad89290c765Tom Hudson size_t* trailing = nullptr) 198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com{ 200d50bc14901ee87552224ee4f1ec84f2f1db7320bungeman@google.com size_t lengthBreak = paint.breakText(text, stop - text, margin); 210d50bc14901ee87552224ee4f1ec84f2f1db7320bungeman@google.com 220d50bc14901ee87552224ee4f1ec84f2f1db7320bungeman@google.com //Check for white space or line breakers before the lengthBreak 230d50bc14901ee87552224ee4f1ec84f2f1db7320bungeman@google.com const char* start = text; 240d50bc14901ee87552224ee4f1ec84f2f1db7320bungeman@google.com const char* word_start = text; 250d50bc14901ee87552224ee4f1ec84f2f1db7320bungeman@google.com int prevWS = true; 260d50bc14901ee87552224ee4f1ec84f2f1db7320bungeman@google.com if (trailing) { 270d50bc14901ee87552224ee4f1ec84f2f1db7320bungeman@google.com *trailing = 0; 280d50bc14901ee87552224ee4f1ec84f2f1db7320bungeman@google.com } 290d50bc14901ee87552224ee4f1ec84f2f1db7320bungeman@google.com 300d50bc14901ee87552224ee4f1ec84f2f1db7320bungeman@google.com while (text < stop) { 310d50bc14901ee87552224ee4f1ec84f2f1db7320bungeman@google.com const char* prevText = text; 320d50bc14901ee87552224ee4f1ec84f2f1db7320bungeman@google.com SkUnichar uni = SkUTF8_NextUnichar(&text); 330d50bc14901ee87552224ee4f1ec84f2f1db7320bungeman@google.com int currWS = is_ws(uni); 340d50bc14901ee87552224ee4f1ec84f2f1db7320bungeman@google.com 350d50bc14901ee87552224ee4f1ec84f2f1db7320bungeman@google.com if (!currWS && prevWS) { 360d50bc14901ee87552224ee4f1ec84f2f1db7320bungeman@google.com word_start = prevText; 370d50bc14901ee87552224ee4f1ec84f2f1db7320bungeman@google.com } 380d50bc14901ee87552224ee4f1ec84f2f1db7320bungeman@google.com prevWS = currWS; 390d50bc14901ee87552224ee4f1ec84f2f1db7320bungeman@google.com 400d50bc14901ee87552224ee4f1ec84f2f1db7320bungeman@google.com if (text > start + lengthBreak) { 410d50bc14901ee87552224ee4f1ec84f2f1db7320bungeman@google.com if (currWS) { 420d50bc14901ee87552224ee4f1ec84f2f1db7320bungeman@google.com // eat the rest of the whitespace 430d50bc14901ee87552224ee4f1ec84f2f1db7320bungeman@google.com while (text < stop && is_ws(SkUTF8_ToUnichar(text))) { 440d50bc14901ee87552224ee4f1ec84f2f1db7320bungeman@google.com text += SkUTF8_CountUTF8Bytes(text); 450d50bc14901ee87552224ee4f1ec84f2f1db7320bungeman@google.com } 460d50bc14901ee87552224ee4f1ec84f2f1db7320bungeman@google.com if (trailing) { 470d50bc14901ee87552224ee4f1ec84f2f1db7320bungeman@google.com *trailing = text - prevText; 480d50bc14901ee87552224ee4f1ec84f2f1db7320bungeman@google.com } 490d50bc14901ee87552224ee4f1ec84f2f1db7320bungeman@google.com } else { 500d50bc14901ee87552224ee4f1ec84f2f1db7320bungeman@google.com // backup until a whitespace (or 1 char) 510d50bc14901ee87552224ee4f1ec84f2f1db7320bungeman@google.com if (word_start == start) { 520d50bc14901ee87552224ee4f1ec84f2f1db7320bungeman@google.com if (prevText > start) { 530d50bc14901ee87552224ee4f1ec84f2f1db7320bungeman@google.com text = prevText; 540d50bc14901ee87552224ee4f1ec84f2f1db7320bungeman@google.com } 550d50bc14901ee87552224ee4f1ec84f2f1db7320bungeman@google.com } else { 560d50bc14901ee87552224ee4f1ec84f2f1db7320bungeman@google.com text = word_start; 570d50bc14901ee87552224ee4f1ec84f2f1db7320bungeman@google.com } 580d50bc14901ee87552224ee4f1ec84f2f1db7320bungeman@google.com } 590d50bc14901ee87552224ee4f1ec84f2f1db7320bungeman@google.com break; 600d50bc14901ee87552224ee4f1ec84f2f1db7320bungeman@google.com } 610d50bc14901ee87552224ee4f1ec84f2f1db7320bungeman@google.com 620d50bc14901ee87552224ee4f1ec84f2f1db7320bungeman@google.com if ('\n' == uni) { 630d50bc14901ee87552224ee4f1ec84f2f1db7320bungeman@google.com size_t ret = text - start; 640d50bc14901ee87552224ee4f1ec84f2f1db7320bungeman@google.com size_t lineBreakSize = 1; 650d50bc14901ee87552224ee4f1ec84f2f1db7320bungeman@google.com if (text < stop) { 660d50bc14901ee87552224ee4f1ec84f2f1db7320bungeman@google.com uni = SkUTF8_NextUnichar(&text); 670d50bc14901ee87552224ee4f1ec84f2f1db7320bungeman@google.com if ('\r' == uni) { 680d50bc14901ee87552224ee4f1ec84f2f1db7320bungeman@google.com ret = text - start; 690d50bc14901ee87552224ee4f1ec84f2f1db7320bungeman@google.com ++lineBreakSize; 700d50bc14901ee87552224ee4f1ec84f2f1db7320bungeman@google.com } 710d50bc14901ee87552224ee4f1ec84f2f1db7320bungeman@google.com } 720d50bc14901ee87552224ee4f1ec84f2f1db7320bungeman@google.com if (trailing) { 730d50bc14901ee87552224ee4f1ec84f2f1db7320bungeman@google.com *trailing = lineBreakSize; 740d50bc14901ee87552224ee4f1ec84f2f1db7320bungeman@google.com } 750d50bc14901ee87552224ee4f1ec84f2f1db7320bungeman@google.com return ret; 760d50bc14901ee87552224ee4f1ec84f2f1db7320bungeman@google.com } 770d50bc14901ee87552224ee4f1ec84f2f1db7320bungeman@google.com 780d50bc14901ee87552224ee4f1ec84f2f1db7320bungeman@google.com if ('\r' == uni) { 790d50bc14901ee87552224ee4f1ec84f2f1db7320bungeman@google.com size_t ret = text - start; 800d50bc14901ee87552224ee4f1ec84f2f1db7320bungeman@google.com size_t lineBreakSize = 1; 810d50bc14901ee87552224ee4f1ec84f2f1db7320bungeman@google.com if (text < stop) { 820d50bc14901ee87552224ee4f1ec84f2f1db7320bungeman@google.com uni = SkUTF8_NextUnichar(&text); 830d50bc14901ee87552224ee4f1ec84f2f1db7320bungeman@google.com if ('\n' == uni) { 840d50bc14901ee87552224ee4f1ec84f2f1db7320bungeman@google.com ret = text - start; 850d50bc14901ee87552224ee4f1ec84f2f1db7320bungeman@google.com ++lineBreakSize; 860d50bc14901ee87552224ee4f1ec84f2f1db7320bungeman@google.com } 870d50bc14901ee87552224ee4f1ec84f2f1db7320bungeman@google.com } 880d50bc14901ee87552224ee4f1ec84f2f1db7320bungeman@google.com if (trailing) { 890d50bc14901ee87552224ee4f1ec84f2f1db7320bungeman@google.com *trailing = lineBreakSize; 900d50bc14901ee87552224ee4f1ec84f2f1db7320bungeman@google.com } 910d50bc14901ee87552224ee4f1ec84f2f1db7320bungeman@google.com return ret; 920d50bc14901ee87552224ee4f1ec84f2f1db7320bungeman@google.com } 930d50bc14901ee87552224ee4f1ec84f2f1db7320bungeman@google.com } 940d50bc14901ee87552224ee4f1ec84f2f1db7320bungeman@google.com 950d50bc14901ee87552224ee4f1ec84f2f1db7320bungeman@google.com return text - start; 968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comint SkTextLineBreaker::CountLines(const char text[], size_t len, const SkPaint& paint, SkScalar width) 998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com{ 1008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com const char* stop = text + len; 1018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com int count = 0; 1028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (width > 0) 1048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com { 1058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com do { 1068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com count += 1; 1078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com text += linebreak(text, stop, paint, width); 1088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } while (text < stop); 1098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 1108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return count; 1118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 1128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com////////////////////////////////////////////////////////////////////////////// 1148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comSkTextBox::SkTextBox() 1168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com{ 1178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fBox.setEmpty(); 1188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fSpacingMul = SK_Scalar1; 1198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fSpacingAdd = 0; 1208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fMode = kLineBreak_Mode; 1218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fSpacingAlign = kStart_SpacingAlign; 1228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 1238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkTextBox::setMode(Mode mode) 1258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com{ 1268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkASSERT((unsigned)mode < kModeCount); 1278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fMode = SkToU8(mode); 1288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 1298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkTextBox::setSpacingAlign(SpacingAlign align) 1318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com{ 1328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkASSERT((unsigned)align < kSpacingAlignCount); 1338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fSpacingAlign = SkToU8(align); 1348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 1358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkTextBox::getBox(SkRect* box) const 1378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com{ 1388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (box) 1398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com *box = fBox; 1408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 1418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkTextBox::setBox(const SkRect& box) 1438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com{ 1448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fBox = box; 1458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 1468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkTextBox::setBox(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom) 1488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com{ 1498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fBox.set(left, top, right, bottom); 1508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 1518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkTextBox::getSpacing(SkScalar* mul, SkScalar* add) const 1538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com{ 1548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (mul) 1558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com *mul = fSpacingMul; 1568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (add) 1578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com *add = fSpacingAdd; 1588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 1598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkTextBox::setSpacing(SkScalar mul, SkScalar add) 1618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com{ 1628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fSpacingMul = mul; 1638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fSpacingAdd = add; 1648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 1658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com///////////////////////////////////////////////////////////////////////////////////////////// 1678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1681b6ab4417e0edef3b91d150e6650205f49f04d17reedSkScalar SkTextBox::visit(Visitor& visitor, const char text[], size_t len, 1691b6ab4417e0edef3b91d150e6650205f49f04d17reed const SkPaint& paint) const { 1708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkScalar marginWidth = fBox.width(); 1718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1721b6ab4417e0edef3b91d150e6650205f49f04d17reed if (marginWidth <= 0 || len == 0) { 1731b6ab4417e0edef3b91d150e6650205f49f04d17reed return fBox.top(); 1741b6ab4417e0edef3b91d150e6650205f49f04d17reed } 1758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com const char* textStop = text + len; 1778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkScalar x, y, scaledSpacing, height, fontHeight; 1798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkPaint::FontMetrics metrics; 1808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com switch (paint.getTextAlign()) { 1828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com case SkPaint::kLeft_Align: 1838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com x = 0; 1848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com break; 1858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com case SkPaint::kCenter_Align: 1868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com x = SkScalarHalf(marginWidth); 1878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com break; 1888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com default: 1898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com x = marginWidth; 1908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com break; 1918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 1928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com x += fBox.fLeft; 1938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fontHeight = paint.getFontMetrics(&metrics); 1958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com scaledSpacing = SkScalarMul(fontHeight, fSpacingMul) + fSpacingAdd; 1968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com height = fBox.height(); 1978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // compute Y position for first line 1998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com { 2008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkScalar textHeight = fontHeight; 2018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 2021b6ab4417e0edef3b91d150e6650205f49f04d17reed if (fMode == kLineBreak_Mode && fSpacingAlign != kStart_SpacingAlign) { 2038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com int count = SkTextLineBreaker::CountLines(text, textStop - text, paint, marginWidth); 2048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkASSERT(count > 0); 2058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com textHeight += scaledSpacing * (count - 1); 2068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 2078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 2088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com switch (fSpacingAlign) { 2098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com case kStart_SpacingAlign: 2108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com y = 0; 2118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com break; 2128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com case kCenter_SpacingAlign: 2138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com y = SkScalarHalf(height - textHeight); 2148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com break; 2158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com default: 2168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkASSERT(fSpacingAlign == kEnd_SpacingAlign); 2178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com y = height - textHeight; 2188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com break; 2198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 2208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com y += fBox.fTop - metrics.fAscent; 2218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 2228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 2231b6ab4417e0edef3b91d150e6650205f49f04d17reed for (;;) { 2240d50bc14901ee87552224ee4f1ec84f2f1db7320bungeman@google.com size_t trailing; 2250d50bc14901ee87552224ee4f1ec84f2f1db7320bungeman@google.com len = linebreak(text, textStop, paint, marginWidth, &trailing); 2261b6ab4417e0edef3b91d150e6650205f49f04d17reed if (y + metrics.fDescent + metrics.fLeading > 0) { 2271b6ab4417e0edef3b91d150e6650205f49f04d17reed visitor(text, len - trailing, x, y, paint); 2281b6ab4417e0edef3b91d150e6650205f49f04d17reed } 2298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com text += len; 2301b6ab4417e0edef3b91d150e6650205f49f04d17reed if (text >= textStop) { 2318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com break; 2321b6ab4417e0edef3b91d150e6650205f49f04d17reed } 2338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com y += scaledSpacing; 2341b6ab4417e0edef3b91d150e6650205f49f04d17reed if (y + metrics.fAscent >= fBox.fBottom) { 2358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com break; 2361b6ab4417e0edef3b91d150e6650205f49f04d17reed } 237d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com } 2381b6ab4417e0edef3b91d150e6650205f49f04d17reed return y + metrics.fDescent + metrics.fLeading; 2398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 2408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 241033e03cb191aff56e06e5d6aab917f60740dba63reed@android.com/////////////////////////////////////////////////////////////////////////////// 242033e03cb191aff56e06e5d6aab917f60740dba63reed@android.com 2431b6ab4417e0edef3b91d150e6650205f49f04d17reedclass CanvasVisitor : public SkTextBox::Visitor { 2441b6ab4417e0edef3b91d150e6650205f49f04d17reed SkCanvas* fCanvas; 2451b6ab4417e0edef3b91d150e6650205f49f04d17reedpublic: 2461b6ab4417e0edef3b91d150e6650205f49f04d17reed CanvasVisitor(SkCanvas* canvas) : fCanvas(canvas) {} 247283b5878e7225a49511cbd3f0fa12603a51319dftfarina 248283b5878e7225a49511cbd3f0fa12603a51319dftfarina void operator()(const char text[], size_t length, SkScalar x, SkScalar y, 249283b5878e7225a49511cbd3f0fa12603a51319dftfarina const SkPaint& paint) override { 2501b6ab4417e0edef3b91d150e6650205f49f04d17reed fCanvas->drawText(text, length, x, y, paint); 2511b6ab4417e0edef3b91d150e6650205f49f04d17reed } 2521b6ab4417e0edef3b91d150e6650205f49f04d17reed}; 2531b6ab4417e0edef3b91d150e6650205f49f04d17reed 254033e03cb191aff56e06e5d6aab917f60740dba63reed@android.comvoid SkTextBox::setText(const char text[], size_t len, const SkPaint& paint) { 255033e03cb191aff56e06e5d6aab917f60740dba63reed@android.com fText = text; 256033e03cb191aff56e06e5d6aab917f60740dba63reed@android.com fLen = len; 257033e03cb191aff56e06e5d6aab917f60740dba63reed@android.com fPaint = &paint; 258033e03cb191aff56e06e5d6aab917f60740dba63reed@android.com} 259033e03cb191aff56e06e5d6aab917f60740dba63reed@android.com 2601b6ab4417e0edef3b91d150e6650205f49f04d17reedvoid SkTextBox::draw(SkCanvas* canvas, const char text[], size_t len, const SkPaint& paint) { 2611b6ab4417e0edef3b91d150e6650205f49f04d17reed CanvasVisitor sink(canvas); 2621b6ab4417e0edef3b91d150e6650205f49f04d17reed this->visit(sink, text, len, paint); 2631b6ab4417e0edef3b91d150e6650205f49f04d17reed} 2641b6ab4417e0edef3b91d150e6650205f49f04d17reed 265033e03cb191aff56e06e5d6aab917f60740dba63reed@android.comvoid SkTextBox::draw(SkCanvas* canvas) { 266033e03cb191aff56e06e5d6aab917f60740dba63reed@android.com this->draw(canvas, fText, fLen, *fPaint); 267033e03cb191aff56e06e5d6aab917f60740dba63reed@android.com} 268033e03cb191aff56e06e5d6aab917f60740dba63reed@android.com 269033e03cb191aff56e06e5d6aab917f60740dba63reed@android.comint SkTextBox::countLines() const { 270033e03cb191aff56e06e5d6aab917f60740dba63reed@android.com return SkTextLineBreaker::CountLines(fText, fLen, *fPaint, fBox.width()); 271033e03cb191aff56e06e5d6aab917f60740dba63reed@android.com} 272033e03cb191aff56e06e5d6aab917f60740dba63reed@android.com 273033e03cb191aff56e06e5d6aab917f60740dba63reed@android.comSkScalar SkTextBox::getTextHeight() const { 274033e03cb191aff56e06e5d6aab917f60740dba63reed@android.com SkScalar spacing = SkScalarMul(fPaint->getTextSize(), fSpacingMul) + fSpacingAdd; 275033e03cb191aff56e06e5d6aab917f60740dba63reed@android.com return this->countLines() * spacing; 276033e03cb191aff56e06e5d6aab917f60740dba63reed@android.com} 2771b6ab4417e0edef3b91d150e6650205f49f04d17reed 2781b6ab4417e0edef3b91d150e6650205f49f04d17reed/////////////////////////////////////////////////////////////////////////////// 2791b6ab4417e0edef3b91d150e6650205f49f04d17reed 2801b6ab4417e0edef3b91d150e6650205f49f04d17reed#include "SkTextBlob.h" 2811b6ab4417e0edef3b91d150e6650205f49f04d17reed 2821b6ab4417e0edef3b91d150e6650205f49f04d17reedclass TextBlobVisitor : public SkTextBox::Visitor { 2831b6ab4417e0edef3b91d150e6650205f49f04d17reedpublic: 2841b6ab4417e0edef3b91d150e6650205f49f04d17reed SkTextBlobBuilder fBuilder; 285283b5878e7225a49511cbd3f0fa12603a51319dftfarina 286283b5878e7225a49511cbd3f0fa12603a51319dftfarina void operator()(const char text[], size_t length, SkScalar x, SkScalar y, 287283b5878e7225a49511cbd3f0fa12603a51319dftfarina const SkPaint& paint) override { 2881b6ab4417e0edef3b91d150e6650205f49f04d17reed SkPaint p(paint); 2891b6ab4417e0edef3b91d150e6650205f49f04d17reed p.setTextEncoding(SkPaint::kGlyphID_TextEncoding); 2901b6ab4417e0edef3b91d150e6650205f49f04d17reed const int count = paint.countText(text, length); 2911b6ab4417e0edef3b91d150e6650205f49f04d17reed paint.textToGlyphs(text, length, fBuilder.allocRun(p, count, x, y).glyphs); 2921b6ab4417e0edef3b91d150e6650205f49f04d17reed } 2931b6ab4417e0edef3b91d150e6650205f49f04d17reed}; 2941b6ab4417e0edef3b91d150e6650205f49f04d17reed 2951b6ab4417e0edef3b91d150e6650205f49f04d17reedSkTextBlob* SkTextBox::snapshotTextBlob(SkScalar* computedBottom) const { 2961b6ab4417e0edef3b91d150e6650205f49f04d17reed TextBlobVisitor visitor; 2971b6ab4417e0edef3b91d150e6650205f49f04d17reed SkScalar newB = this->visit(visitor, fText, fLen, *fPaint); 2981b6ab4417e0edef3b91d150e6650205f49f04d17reed if (computedBottom) { 2991b6ab4417e0edef3b91d150e6650205f49f04d17reed *computedBottom = newB; 3001b6ab4417e0edef3b91d150e6650205f49f04d17reed } 3011b6ab4417e0edef3b91d150e6650205f49f04d17reed return (SkTextBlob*)visitor.fBuilder.build(); 3021b6ab4417e0edef3b91d150e6650205f49f04d17reed} 3031b6ab4417e0edef3b91d150e6650205f49f04d17reed 304