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