1ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com/* 2ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Copyright 2011 Google Inc. 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 */ 78a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 83d1cb97240c568253b657b8a1e50258792457166mike@reedtribe.org#include "gm.h" 933d2055e594177b27360f84e0631b26d74a55a9bMike Klein#include "sk_tool_utils.h" 10b7061176c7f414616fe2e79e832b3e0abe326af6robertphillips@google.com#include "SkBlurMask.h" 11b7061176c7f414616fe2e79e832b3e0abe326af6robertphillips@google.com#include "SkBlurMaskFilter.h" 128b0e8ac5f582de80356019406e2975079bf0829dcommit-bot@chromium.org#include "SkReadBuffer.h" 13eae6a9127707b9391546012d11bcc7d9920dfa6dfmalita#include "SkTextBlob.h" 148b0e8ac5f582de80356019406e2975079bf0829dcommit-bot@chromium.org#include "SkWriteBuffer.h" 158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "Sk2DPathEffect.h" 178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 180449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclarkstatic SkPath create_underline(const SkTDArray<SkScalar>& intersections, 190449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark SkScalar last, SkScalar finalPos, 200449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark SkScalar uPos, SkScalar uWidth, SkScalar textSize) { 210449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark SkPath underline; 220449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark SkScalar end = last; 230449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark for (int index = 0; index < intersections.count(); index += 2) { 240449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark SkScalar start = intersections[index] - uWidth;; 250449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark end = intersections[index + 1] + uWidth; 260449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark if (start > last && last + textSize / 12 < start) { 270449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark underline.moveTo(last, uPos); 280449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark underline.lineTo(start, uPos); 290449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark } 300449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark last = end; 310449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark } 320449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark if (end < finalPos) { 330449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark underline.moveTo(end, uPos); 340449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark underline.lineTo(finalPos, uPos); 350449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark } 360449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark return underline; 370449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark} 380449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark 390449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclarkstatic void find_intercepts(const char* test, size_t len, SkScalar x, SkScalar y, 400449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark const SkPaint& paint, SkScalar uWidth, SkTDArray<SkScalar>* intersections) { 410449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark SkScalar uPos = y + uWidth; 420449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark SkScalar bounds[2] = { uPos - uWidth / 2, uPos + uWidth / 2 }; 430449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark int count = paint.getTextIntercepts(test, len, x, y, bounds, nullptr); 440449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark SkASSERT(!(count % 2)); 450449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark if (count) { 460449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark intersections->setCount(count); 470449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark paint.getTextIntercepts(test, len, x, y, bounds, intersections->begin()); 480449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark } 490449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark} 500449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark 510449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclarkDEF_SIMPLE_GM(fancyunderline, canvas, 900, 1350) { 520449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark SkPaint paint; 530449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark paint.setAntiAlias(true); 540449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark const char* fam[] = { "sans-serif", "serif", "monospace" }; 550449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark const char test[] = "aAjJgGyY_|{-(~[,]qQ}pP}zZ"; 560449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark SkPoint textPt = { 10, 80 }; 57eae6a9127707b9391546012d11bcc7d9920dfa6dfmalita for (size_t font = 0; font < SK_ARRAY_COUNT(fam); ++font) { 58ee6a9919a362e16c1d84a870ce867d1ad7b8a141mboc sk_tool_utils::set_portable_typeface(&paint, fam[font]); 590449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark for (SkScalar textSize = 100; textSize > 10; textSize -= 20) { 600449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark paint.setTextSize(textSize); 610449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark const SkScalar uWidth = textSize / 15; 620449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark paint.setStrokeWidth(uWidth); 630449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark paint.setStyle(SkPaint::kFill_Style); 640449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark canvas->drawText(test, sizeof(test) - 1, textPt.fX, textPt.fY, paint); 650449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark 660449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark SkTDArray<SkScalar> intersections; 670449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark find_intercepts(test, sizeof(test) - 1, textPt.fX, textPt.fY, paint, uWidth, 680449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark &intersections); 690449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark 700449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark SkScalar start = textPt.fX; 710449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark SkScalar end = paint.measureText(test, sizeof(test) - 1) + textPt.fX; 720449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark SkScalar uPos = textPt.fY + uWidth; 730449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark SkPath underline = create_underline(intersections, start, end, uPos, uWidth, textSize); 740449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark paint.setStyle(SkPaint::kStroke_Style); 750449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark canvas->drawPath(underline, paint); 760449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark 770449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark canvas->translate(0, textSize * 1.3f); 780449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark } 790449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark canvas->translate(0, 60); 800449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark } 810449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark} 820449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark 830449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclarkstatic void find_intercepts(const char* test, size_t len, const SkPoint* pos, const SkPaint& paint, 840449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark SkScalar uWidth, SkTDArray<SkScalar>* intersections) { 850449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark SkScalar uPos = pos[0].fY + uWidth; 860449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark SkScalar bounds[2] = { uPos - uWidth / 2, uPos + uWidth / 2 }; 870449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark int count = paint.getPosTextIntercepts(test, len, pos, bounds, nullptr); 880449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark SkASSERT(!(count % 2)); 890449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark if (count) { 900449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark intersections->setCount(count); 910449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark paint.getPosTextIntercepts(test, len, pos, bounds, intersections->begin()); 920449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark } 930449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark} 940449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark 950449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclarkDEF_SIMPLE_GM(fancyposunderline, canvas, 900, 1350) { 960449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark SkPaint paint; 970449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark paint.setAntiAlias(true); 980449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark const char* fam[] = { "sans-serif", "serif", "monospace" }; 990449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark const char test[] = "aAjJgGyY_|{-(~[,]qQ}pP}zZ"; 1000449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark SkPoint textPt = { 10, 80 }; 101eae6a9127707b9391546012d11bcc7d9920dfa6dfmalita for (size_t font = 0; font < SK_ARRAY_COUNT(fam); ++font) { 102ee6a9919a362e16c1d84a870ce867d1ad7b8a141mboc sk_tool_utils::set_portable_typeface(&paint, fam[font]); 1030449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark for (SkScalar textSize = 100; textSize > 10; textSize -= 20) { 1040449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark paint.setTextSize(textSize); 1050449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark const SkScalar uWidth = textSize / 15; 1060449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark paint.setStrokeWidth(uWidth); 1070449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark paint.setStyle(SkPaint::kFill_Style); 1080449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark int widthCount = paint.getTextWidths(test, sizeof(test) - 1, nullptr); 1090449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark SkTDArray<SkScalar> widths; 1100449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark widths.setCount(widthCount); 1110449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark (void) paint.getTextWidths(test, sizeof(test) - 1, widths.begin()); 1120449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark SkTDArray<SkPoint> pos; 1130449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark pos.setCount(widthCount); 1140449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark SkScalar posX = textPt.fX; 1150449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark for (int index = 0; index < widthCount; ++index) { 1160449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark pos[index].fX = posX; 1170449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark posX += widths[index]; 1180449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark pos[index].fY = textPt.fY + (textSize / 25) * (index % 4); 1190449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark } 1200449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark canvas->drawPosText(test, sizeof(test) - 1, pos.begin(), paint); 1210449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark 1220449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark SkTDArray<SkScalar> intersections; 1230449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark find_intercepts(test, sizeof(test) - 1, pos.begin(), paint, uWidth, &intersections); 1240449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark 1250449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark SkScalar start = textPt.fX; 1260449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark SkScalar end = posX; 1270449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark SkScalar uPos = textPt.fY + uWidth; 1280449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark SkPath underline = create_underline(intersections, start, end, uPos, uWidth, textSize); 1290449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark paint.setStyle(SkPaint::kStroke_Style); 1300449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark canvas->drawPath(underline, paint); 1310449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark 1320449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark canvas->translate(0, textSize * 1.3f); 1330449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark } 1340449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark canvas->translate(0, 60); 1350449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark } 1360449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark} 1370449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark 138eae6a9127707b9391546012d11bcc7d9920dfa6dfmalitanamespace { 139eae6a9127707b9391546012d11bcc7d9920dfa6dfmalita 14037283c28aa5bea2204c18956e74f83b238d7a891fmalitask_sp<SkTextBlob> MakeFancyBlob(const SkPaint& paint, const char* text) { 141eae6a9127707b9391546012d11bcc7d9920dfa6dfmalita SkPaint blobPaint(paint); 142eae6a9127707b9391546012d11bcc7d9920dfa6dfmalita 143eae6a9127707b9391546012d11bcc7d9920dfa6dfmalita const size_t textLen = strlen(text); 144eae6a9127707b9391546012d11bcc7d9920dfa6dfmalita const int glyphCount = blobPaint.textToGlyphs(text, textLen, nullptr); 145eae6a9127707b9391546012d11bcc7d9920dfa6dfmalita SkAutoTArray<SkGlyphID> glyphs(glyphCount); 146eae6a9127707b9391546012d11bcc7d9920dfa6dfmalita blobPaint.textToGlyphs(text, textLen, glyphs.get()); 147eae6a9127707b9391546012d11bcc7d9920dfa6dfmalita 148eae6a9127707b9391546012d11bcc7d9920dfa6dfmalita blobPaint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); 149eae6a9127707b9391546012d11bcc7d9920dfa6dfmalita const size_t glyphTextBytes = SkTo<uint32_t>(glyphCount) * sizeof(SkGlyphID); 150eae6a9127707b9391546012d11bcc7d9920dfa6dfmalita const int widthCount = blobPaint.getTextWidths(glyphs.get(), glyphTextBytes, nullptr); 151eae6a9127707b9391546012d11bcc7d9920dfa6dfmalita SkAssertResult(widthCount == glyphCount); 152eae6a9127707b9391546012d11bcc7d9920dfa6dfmalita 153eae6a9127707b9391546012d11bcc7d9920dfa6dfmalita SkAutoTArray<SkScalar> widths(glyphCount); 154eae6a9127707b9391546012d11bcc7d9920dfa6dfmalita blobPaint.getTextWidths(glyphs.get(), glyphTextBytes, widths.get()); 155eae6a9127707b9391546012d11bcc7d9920dfa6dfmalita 156eae6a9127707b9391546012d11bcc7d9920dfa6dfmalita SkTextBlobBuilder blobBuilder; 157eae6a9127707b9391546012d11bcc7d9920dfa6dfmalita int glyphIndex = 0; 158eae6a9127707b9391546012d11bcc7d9920dfa6dfmalita SkScalar advance = 0; 159eae6a9127707b9391546012d11bcc7d9920dfa6dfmalita 160eae6a9127707b9391546012d11bcc7d9920dfa6dfmalita // Default-positioned run. 161eae6a9127707b9391546012d11bcc7d9920dfa6dfmalita { 162eae6a9127707b9391546012d11bcc7d9920dfa6dfmalita const int defaultRunLen = glyphCount / 3; 163eae6a9127707b9391546012d11bcc7d9920dfa6dfmalita const SkTextBlobBuilder::RunBuffer& buf = blobBuilder.allocRun(blobPaint, 164eae6a9127707b9391546012d11bcc7d9920dfa6dfmalita defaultRunLen, 165eae6a9127707b9391546012d11bcc7d9920dfa6dfmalita advance, 0); 166eae6a9127707b9391546012d11bcc7d9920dfa6dfmalita memcpy(buf.glyphs, glyphs.get(), SkTo<uint32_t>(defaultRunLen) * sizeof(SkGlyphID)); 167eae6a9127707b9391546012d11bcc7d9920dfa6dfmalita 168eae6a9127707b9391546012d11bcc7d9920dfa6dfmalita for (int i = 0; i < defaultRunLen; ++i) { 169eae6a9127707b9391546012d11bcc7d9920dfa6dfmalita advance += widths[glyphIndex++]; 170eae6a9127707b9391546012d11bcc7d9920dfa6dfmalita } 171eae6a9127707b9391546012d11bcc7d9920dfa6dfmalita } 172eae6a9127707b9391546012d11bcc7d9920dfa6dfmalita 173eae6a9127707b9391546012d11bcc7d9920dfa6dfmalita // Horizontal-positioned run. 174eae6a9127707b9391546012d11bcc7d9920dfa6dfmalita { 175eae6a9127707b9391546012d11bcc7d9920dfa6dfmalita const int horizontalRunLen = glyphCount / 3; 176eae6a9127707b9391546012d11bcc7d9920dfa6dfmalita const SkTextBlobBuilder::RunBuffer& buf = blobBuilder.allocRunPosH(blobPaint, 177eae6a9127707b9391546012d11bcc7d9920dfa6dfmalita horizontalRunLen, 178eae6a9127707b9391546012d11bcc7d9920dfa6dfmalita 0); 179eae6a9127707b9391546012d11bcc7d9920dfa6dfmalita memcpy(buf.glyphs, glyphs.get() + glyphIndex, 180eae6a9127707b9391546012d11bcc7d9920dfa6dfmalita SkTo<uint32_t>(horizontalRunLen) * sizeof(SkGlyphID)); 181eae6a9127707b9391546012d11bcc7d9920dfa6dfmalita for (int i = 0; i < horizontalRunLen; ++i) { 182eae6a9127707b9391546012d11bcc7d9920dfa6dfmalita buf.pos[i] = advance; 183eae6a9127707b9391546012d11bcc7d9920dfa6dfmalita advance += widths[glyphIndex++]; 184eae6a9127707b9391546012d11bcc7d9920dfa6dfmalita } 185eae6a9127707b9391546012d11bcc7d9920dfa6dfmalita } 186eae6a9127707b9391546012d11bcc7d9920dfa6dfmalita 187eae6a9127707b9391546012d11bcc7d9920dfa6dfmalita // Full-positioned run. 188eae6a9127707b9391546012d11bcc7d9920dfa6dfmalita { 189eae6a9127707b9391546012d11bcc7d9920dfa6dfmalita const int fullRunLen = glyphCount - glyphIndex; 190eae6a9127707b9391546012d11bcc7d9920dfa6dfmalita const SkTextBlobBuilder::RunBuffer& buf = blobBuilder.allocRunPos(blobPaint, fullRunLen); 191eae6a9127707b9391546012d11bcc7d9920dfa6dfmalita memcpy(buf.glyphs, glyphs.get() + glyphIndex, 192eae6a9127707b9391546012d11bcc7d9920dfa6dfmalita SkTo<uint32_t>(fullRunLen) * sizeof(SkGlyphID)); 193eae6a9127707b9391546012d11bcc7d9920dfa6dfmalita for (int i = 0; i < fullRunLen; ++i) { 194eae6a9127707b9391546012d11bcc7d9920dfa6dfmalita buf.pos[i * 2 + 0] = advance; // x offset 195eae6a9127707b9391546012d11bcc7d9920dfa6dfmalita buf.pos[i * 2 + 1] = 0; // y offset 196eae6a9127707b9391546012d11bcc7d9920dfa6dfmalita advance += widths[glyphIndex++]; 197eae6a9127707b9391546012d11bcc7d9920dfa6dfmalita } 198eae6a9127707b9391546012d11bcc7d9920dfa6dfmalita } 199eae6a9127707b9391546012d11bcc7d9920dfa6dfmalita 20037283c28aa5bea2204c18956e74f83b238d7a891fmalita return blobBuilder.make(); 201eae6a9127707b9391546012d11bcc7d9920dfa6dfmalita} 202eae6a9127707b9391546012d11bcc7d9920dfa6dfmalita 203eae6a9127707b9391546012d11bcc7d9920dfa6dfmalita} // anonymous ns 204eae6a9127707b9391546012d11bcc7d9920dfa6dfmalita 205eae6a9127707b9391546012d11bcc7d9920dfa6dfmalitaDEF_SIMPLE_GM(fancyblobunderline, canvas, 1480, 1380) { 206eae6a9127707b9391546012d11bcc7d9920dfa6dfmalita SkPaint paint; 207eae6a9127707b9391546012d11bcc7d9920dfa6dfmalita paint.setAntiAlias(true); 208eae6a9127707b9391546012d11bcc7d9920dfa6dfmalita const char* fam[] = { "sans-serif", "serif", "monospace" }; 209eae6a9127707b9391546012d11bcc7d9920dfa6dfmalita const char test[] = "aAjJgGyY_|{-(~[,]qQ}pP}zZ"; 210eae6a9127707b9391546012d11bcc7d9920dfa6dfmalita const SkPoint blobOffset = { 10, 80 }; 211eae6a9127707b9391546012d11bcc7d9920dfa6dfmalita 212eae6a9127707b9391546012d11bcc7d9920dfa6dfmalita for (size_t font = 0; font < SK_ARRAY_COUNT(fam); ++font) { 213eae6a9127707b9391546012d11bcc7d9920dfa6dfmalita sk_tool_utils::set_portable_typeface(&paint, fam[font]); 214eae6a9127707b9391546012d11bcc7d9920dfa6dfmalita for (SkScalar textSize = 100; textSize > 10; textSize -= 20) { 215eae6a9127707b9391546012d11bcc7d9920dfa6dfmalita paint.setTextSize(textSize); 216eae6a9127707b9391546012d11bcc7d9920dfa6dfmalita const SkScalar uWidth = textSize / 15; 217eae6a9127707b9391546012d11bcc7d9920dfa6dfmalita paint.setStrokeWidth(uWidth); 218eae6a9127707b9391546012d11bcc7d9920dfa6dfmalita paint.setStyle(SkPaint::kFill_Style); 219eae6a9127707b9391546012d11bcc7d9920dfa6dfmalita 22037283c28aa5bea2204c18956e74f83b238d7a891fmalita sk_sp<SkTextBlob> blob = MakeFancyBlob(paint, test); 22137283c28aa5bea2204c18956e74f83b238d7a891fmalita canvas->drawTextBlob(blob, blobOffset.x(), blobOffset.y(), paint); 222eae6a9127707b9391546012d11bcc7d9920dfa6dfmalita 223eae6a9127707b9391546012d11bcc7d9920dfa6dfmalita const SkScalar uPos = uWidth; 224eae6a9127707b9391546012d11bcc7d9920dfa6dfmalita const SkScalar bounds[2] = { uPos - uWidth / 2, uPos + uWidth / 2 }; 225eae6a9127707b9391546012d11bcc7d9920dfa6dfmalita const int interceptCount = paint.getTextBlobIntercepts(blob.get(), bounds, nullptr); 226eae6a9127707b9391546012d11bcc7d9920dfa6dfmalita SkASSERT(!(interceptCount % 2)); 227eae6a9127707b9391546012d11bcc7d9920dfa6dfmalita 228eae6a9127707b9391546012d11bcc7d9920dfa6dfmalita SkTDArray<SkScalar> intercepts; 229eae6a9127707b9391546012d11bcc7d9920dfa6dfmalita intercepts.setCount(interceptCount); 230eae6a9127707b9391546012d11bcc7d9920dfa6dfmalita paint.getTextBlobIntercepts(blob.get(), bounds, intercepts.begin()); 231eae6a9127707b9391546012d11bcc7d9920dfa6dfmalita 232eae6a9127707b9391546012d11bcc7d9920dfa6dfmalita const SkScalar start = blob->bounds().left(); 233eae6a9127707b9391546012d11bcc7d9920dfa6dfmalita const SkScalar end = blob->bounds().right(); 234eae6a9127707b9391546012d11bcc7d9920dfa6dfmalita SkPath underline = create_underline(intercepts, start, end, uPos, uWidth, textSize); 235eae6a9127707b9391546012d11bcc7d9920dfa6dfmalita underline.offset(blobOffset.x(), blobOffset.y()); 236eae6a9127707b9391546012d11bcc7d9920dfa6dfmalita paint.setStyle(SkPaint::kStroke_Style); 237eae6a9127707b9391546012d11bcc7d9920dfa6dfmalita canvas->drawPath(underline, paint); 238eae6a9127707b9391546012d11bcc7d9920dfa6dfmalita 239eae6a9127707b9391546012d11bcc7d9920dfa6dfmalita canvas->translate(0, textSize * 1.3f); 240eae6a9127707b9391546012d11bcc7d9920dfa6dfmalita } 241eae6a9127707b9391546012d11bcc7d9920dfa6dfmalita 242eae6a9127707b9391546012d11bcc7d9920dfa6dfmalita canvas->translate(0, 60); 243eae6a9127707b9391546012d11bcc7d9920dfa6dfmalita } 244eae6a9127707b9391546012d11bcc7d9920dfa6dfmalita} 245eae6a9127707b9391546012d11bcc7d9920dfa6dfmalita 2460449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclarkDEF_SIMPLE_GM(fancyunderlinebars, canvas, 1500, 460) { 2470449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark SkPaint paint; 2480449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark paint.setAntiAlias(true); 2490449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark const char test[] = " .}]_ .}]_ .}]_ .}]_ .}]_ .}]_ .}]_ .}]_ .}]_ .}]_ .}]_ .}]_ .}]_"; 2500449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark SkPoint textPt = { 10, 80 }; 2510449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark sk_tool_utils::set_portable_typeface(&paint, "serif"); 2520449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark for (SkScalar textSize = 100; textSize > 10; textSize -= 20) { 2530449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark paint.setTextSize(textSize); 2540449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark SkScalar uWidth = textSize / 15; 2550449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark paint.setStrokeWidth(uWidth); 2560449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark paint.setStyle(SkPaint::kFill_Style); 2570449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark int widthCount = paint.getTextWidths(test, sizeof(test) - 1, nullptr); 2580449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark SkTDArray<SkScalar> widths; 2590449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark widths.setCount(widthCount); 2600449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark (void) paint.getTextWidths(test, sizeof(test) - 1, widths.begin()); 2610449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark SkTDArray<SkPoint> pos; 2620449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark pos.setCount(widthCount); 2630449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark SkScalar posX = textPt.fX; 2640449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark pos[0] = textPt; 2650449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark posX += widths[0]; 2660449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark for (int index = 1; index < widthCount; ++index) { 2670449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark pos[index].fX = posX; 2680449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark posX += widths[index]; 2690449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark pos[index].fY = textPt.fY - (textSize / 50) * (index / 5) + textSize / 50 * 4; 2700449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark } 2710449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark canvas->drawPosText(test, sizeof(test) - 1, pos.begin(), paint); 2720449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark 2730449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark SkTDArray<SkScalar> intersections; 2740449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark find_intercepts(test, sizeof(test) - 1, pos.begin(), paint, uWidth, &intersections); 2750449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark 2760449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark SkScalar start = textPt.fX; 2770449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark SkScalar end = posX; 2780449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark SkScalar uPos = pos[0].fY + uWidth; 2790449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark SkPath underline = create_underline(intersections, start, end, uPos, uWidth, textSize); 2800449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark paint.setStyle(SkPaint::kStroke_Style); 2810449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark canvas->drawPath(underline, paint); 2820449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark canvas->translate(0, textSize * 1.3f); 2830449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark } 2840449bcfb2fa1dd33cb3a4c0c8b17960d17edf01acaryclark} 285