diff --git a/gm/aaxfermodes.cpp b/gm/aaxfermodes.cpp index 9cbb583694a2b..19add75139ffb 100644 --- a/gm/aaxfermodes.cpp +++ b/gm/aaxfermodes.cpp @@ -10,6 +10,7 @@ #include "SkColorPriv.h" #include "SkPath.h" #include "SkShader.h" +#include "SkTextUtils.h" enum { kXfermodeCount = (int)SkBlendMode::kLastMode + 1 + 1, // extra for arith @@ -106,14 +107,14 @@ class AAXfermodesGM : public skiagm::GM { canvas->save(); if (kShape_Pass == drawingPass) { - fLabelPaint.setTextAlign(SkPaint::kCenter_Align); - canvas->drawString("Src Unknown", + SkTextUtils::DrawString(canvas, "Src Unknown", kLabelSpacing + kShapeTypeSpacing * 1.5f + kShapeSpacing / 2, - kSubtitleSpacing / 2 + fLabelPaint.getTextSize() / 3, fLabelPaint); - canvas->drawString("Src Opaque", + kSubtitleSpacing / 2 + fLabelPaint.getTextSize() / 3, fLabelPaint, + SkPaint::kCenter_Align); + SkTextUtils::DrawString(canvas, "Src Opaque", kLabelSpacing + kShapeTypeSpacing * 1.5f + kShapeSpacing / 2 + kPaintSpacing, kSubtitleSpacing / 2 + fLabelPaint.getTextSize() / 3, - fLabelPaint); + fLabelPaint, SkPaint::kCenter_Align); } canvas->translate(0, kSubtitleSpacing + kShapeSpacing/2); @@ -179,13 +180,14 @@ class AAXfermodesGM : public skiagm::GM { SkPaint titlePaint(fLabelPaint); titlePaint.setTextSize(9 * titlePaint.getTextSize() / 8); titlePaint.setFakeBoldText(true); - titlePaint.setTextAlign(SkPaint::kCenter_Align); - canvas->drawString("Porter Duff", - kLabelSpacing + 4 * kShapeTypeSpacing, - kTitleSpacing / 2 + titlePaint.getTextSize() / 3, titlePaint); - canvas->drawString("Advanced", - kXfermodeTypeSpacing + kLabelSpacing + 4 * kShapeTypeSpacing, - kTitleSpacing / 2 + titlePaint.getTextSize() / 3, titlePaint); + SkTextUtils::DrawString(canvas, "Porter Duff", + kLabelSpacing + 4 * kShapeTypeSpacing, + kTitleSpacing / 2 + titlePaint.getTextSize() / 3, titlePaint, + SkPaint::kCenter_Align); + SkTextUtils::DrawString(canvas, "Advanced", + kXfermodeTypeSpacing + kLabelSpacing + 4 * kShapeTypeSpacing, + kTitleSpacing / 2 + titlePaint.getTextSize() / 3, titlePaint, + SkPaint::kCenter_Align); draw_pass(canvas, kShape_Pass); canvas->restore(); @@ -193,9 +195,9 @@ class AAXfermodesGM : public skiagm::GM { void drawModeName(SkCanvas* canvas, SkBlendMode mode) { const char* modeName = SkBlendMode_Name(mode); - fLabelPaint.setTextAlign(SkPaint::kRight_Align); - canvas->drawString(modeName, kLabelSpacing - kShapeSize / 4, - fLabelPaint.getTextSize() / 4, fLabelPaint); + SkTextUtils::DrawString(canvas, modeName, kLabelSpacing - kShapeSize / 4, + fLabelPaint.getTextSize() / 4, fLabelPaint, + SkPaint::kRight_Align); } void setupShapePaint(SkCanvas* canvas, SkColor color, SkBlendMode mode, SkPaint* paint) { diff --git a/gm/androidblendmodes.cpp b/gm/androidblendmodes.cpp index 75811ee8ba729..db6a65f2451eb 100644 --- a/gm/androidblendmodes.cpp +++ b/gm/androidblendmodes.cpp @@ -8,6 +8,7 @@ #include "gm.h" #include "sk_tool_utils.h" #include "SkBitmap.h" +#include "SkTextUtils.h" namespace skiagm { @@ -67,7 +68,6 @@ class AndroidBlendModesGM : public GM { SkPaint textPaint; textPaint.setAntiAlias(true); sk_tool_utils::set_portable_typeface(&textPaint); - textPaint.setTextAlign(SkPaint::kCenter_Align); sk_tool_utils::draw_checkerboard(canvas, kWhite, @@ -94,10 +94,10 @@ class AndroidBlendModesGM : public GM { this->drawTile(canvas, xOffset, yOffset, mode); canvas->restoreToCount(saveCount); - canvas->drawString(SkBlendMode_Name(mode), + SkTextUtils::DrawString(canvas, SkBlendMode_Name(mode), xOffset + kBitmapSize/2.0f, yOffset + kBitmapSize, - textPaint); + textPaint, SkPaint::kCenter_Align); xOffset += 256; if (xOffset >= 1024) { diff --git a/gm/tilemodes.cpp b/gm/tilemodes.cpp index f9f6751bccf80..5c48d07dbd4ef 100644 --- a/gm/tilemodes.cpp +++ b/gm/tilemodes.cpp @@ -11,6 +11,7 @@ #include "SkPath.h" #include "SkRegion.h" #include "SkShader.h" +#include "SkTextUtils.h" #include "SkUTF.h" // effects #include "SkGradientShader.h" @@ -104,8 +105,7 @@ class TilingGM : public skiagm::GM { p.setDither(true); str.printf("[%s,%s]", gModeNames[kx], gModeNames[ky]); - p.setTextAlign(SkPaint::kCenter_Align); - canvas->drawString(str, x + r.width()/2, y, p); + SkTextUtils::DrawString(canvas, str, x + r.width()/2, y, p, SkPaint::kCenter_Align); x += r.width() * 4 / 3; } @@ -223,22 +223,20 @@ class Tiling2GM : public skiagm::GM { SkPaint p; p.setAntiAlias(true); sk_tool_utils::set_portable_typeface(&p); - p.setTextAlign(SkPaint::kCenter_Align); for (size_t kx = 0; kx < SK_ARRAY_COUNT(gModes); kx++) { SkString str(gModeNames[kx]); - canvas->drawString(str, x + r.width()/2, y, p); + SkTextUtils::DrawString(canvas, str, x + r.width()/2, y, p, SkPaint::kCenter_Align); x += r.width() * 4 / 3; } y += SkIntToScalar(16) + h; - p.setTextAlign(SkPaint::kRight_Align); for (size_t ky = 0; ky < SK_ARRAY_COUNT(gModes); ky++) { x = SkIntToScalar(16) + w; SkString str(gModeNames[ky]); - canvas->drawString(str, x, y + h/2, p); + SkTextUtils::DrawString(canvas, str, x, y + h/2, p, SkPaint::kRight_Align); x += SkIntToScalar(50); for (size_t kx = 0; kx < SK_ARRAY_COUNT(gModes); kx++) { diff --git a/gm/tilemodes_scaled.cpp b/gm/tilemodes_scaled.cpp index 7d001f1fdd6e9..4a4e494b64f45 100644 --- a/gm/tilemodes_scaled.cpp +++ b/gm/tilemodes_scaled.cpp @@ -11,6 +11,7 @@ #include "SkPath.h" #include "SkRegion.h" #include "SkShader.h" +#include "SkTextUtils.h" #include "SkUTF.h" // effects @@ -106,8 +107,8 @@ class ScaledTilingGM : public skiagm::GM { sk_tool_utils::set_portable_typeface(&p); str.printf("[%s,%s]", gModeNames[kx], gModeNames[ky]); - p.setTextAlign(SkPaint::kCenter_Align); - canvas->drawString(str, scale*(x + r.width()/2), y, p); + SkTextUtils::DrawString(canvas, str, scale*(x + r.width()/2), y, p, + SkPaint::kCenter_Align); x += r.width() * 4 / 3; } @@ -224,22 +225,20 @@ class ScaledTiling2GM : public skiagm::GM { SkPaint p; p.setAntiAlias(true); sk_tool_utils::set_portable_typeface(&p); - p.setTextAlign(SkPaint::kCenter_Align); for (size_t kx = 0; kx < SK_ARRAY_COUNT(gModes); kx++) { SkString str(gModeNames[kx]); - canvas->drawString(str, x + r.width()/2, y, p); + SkTextUtils::DrawString(canvas, str, x + r.width()/2, y, p, SkPaint::kCenter_Align); x += r.width() * 4 / 3; } y += SkIntToScalar(16) + h; - p.setTextAlign(SkPaint::kRight_Align); for (size_t ky = 0; ky < SK_ARRAY_COUNT(gModes); ky++) { x = SkIntToScalar(16) + w; SkString str(gModeNames[ky]); - canvas->drawString(str, x, y + h/2, p); + SkTextUtils::DrawString(canvas, str, x, y + h/2, p, SkPaint::kRight_Align); x += SkIntToScalar(50); for (size_t kx = 0; kx < SK_ARRAY_COUNT(gModes); kx++) { diff --git a/gm/windowrectangles.cpp b/gm/windowrectangles.cpp index e52a7bfc866da..62dd51cdb35a7 100644 --- a/gm/windowrectangles.cpp +++ b/gm/windowrectangles.cpp @@ -9,6 +9,7 @@ #include "sk_tool_utils.h" #include "SkClipStack.h" #include "SkRRect.h" +#include "SkTextUtils.h" #include "GrAppliedClip.h" #include "GrCaps.h" @@ -265,7 +266,6 @@ void WindowRectanglesMaskGM::stencilCheckerboard(GrRenderTargetContext* rtc, boo void WindowRectanglesMaskGM::fail(SkCanvas* canvas) { SkPaint paint; paint.setAntiAlias(true); - paint.setTextAlign(SkPaint::kCenter_Align); paint.setTextSize(20); sk_tool_utils::set_portable_typeface(&paint); @@ -275,8 +275,9 @@ void WindowRectanglesMaskGM::fail(SkCanvas* canvas) { canvas->clipRect(SkRect::Make(kCoverRect)); canvas->clear(SK_ColorWHITE); - canvas->drawString(errorMsg, SkIntToScalar((kCoverRect.left() + kCoverRect.right())/2), - SkIntToScalar((kCoverRect.top() + kCoverRect.bottom())/2 - 10), paint); + SkTextUtils::DrawString(canvas, errorMsg, SkIntToScalar((kCoverRect.left() + kCoverRect.right())/2), + SkIntToScalar((kCoverRect.top() + kCoverRect.bottom())/2 - 10), paint, + SkPaint::kCenter_Align); } DEF_GM( return new WindowRectanglesMaskGM(); ) diff --git a/gm/xfermodes.cpp b/gm/xfermodes.cpp index f71efe3e7710f..4f1b7aa4a9c2e 100644 --- a/gm/xfermodes.cpp +++ b/gm/xfermodes.cpp @@ -9,6 +9,7 @@ #include "sk_tool_utils.h" #include "SkBitmap.h" #include "SkShader.h" +#include "SkTextUtils.h" enum SrcType { //! A WxH image with a rectangle in the lower right. @@ -227,7 +228,6 @@ class XfermodesGM : public skiagm::GM { SkPaint labelP; labelP.setAntiAlias(true); sk_tool_utils::set_portable_typeface(&labelP); - labelP.setTextAlign(SkPaint::kCenter_Align); const int W = 5; @@ -258,8 +258,8 @@ class XfermodesGM : public skiagm::GM { #if 1 const char* label = SkBlendMode_Name(gModes[i].fMode); - canvas->drawString(label, - x + w/2, y - labelP.getTextSize()/2, labelP); + SkTextUtils::DrawString(canvas, label, x + w/2, y - labelP.getTextSize()/2, + labelP, SkPaint::kCenter_Align); #endif x += w + SkIntToScalar(10); if ((i % W) == W - 1) { diff --git a/gm/xfermodes2.cpp b/gm/xfermodes2.cpp index 2db824d95b646..ebec00bfa7944 100644 --- a/gm/xfermodes2.cpp +++ b/gm/xfermodes2.cpp @@ -10,6 +10,7 @@ #include "SkShader.h" #include "SkBlendModePriv.h" #include "SkColorPriv.h" +#include "SkTextUtils.h" namespace skiagm { @@ -35,7 +36,6 @@ class Xfermodes2GM : public GM { SkPaint labelP; labelP.setAntiAlias(true); sk_tool_utils::set_portable_typeface(&labelP); - labelP.setTextAlign(SkPaint::kCenter_Align); const int W = 6; @@ -72,8 +72,9 @@ class Xfermodes2GM : public GM { canvas->restore(); #if 1 - canvas->drawString(SkBlendMode_Name(mode), - x + w/2, y - labelP.getTextSize()/2, labelP); + SkTextUtils::DrawString(canvas, SkBlendMode_Name(mode), + x + w/2, y - labelP.getTextSize()/2, labelP, + SkPaint::kCenter_Align); #endif x += w + SkIntToScalar(10); if ((m % W) == W - 1) { diff --git a/gm/xfermodes3.cpp b/gm/xfermodes3.cpp index 0d13148956eee..9d53c2fd1c311 100644 --- a/gm/xfermodes3.cpp +++ b/gm/xfermodes3.cpp @@ -12,7 +12,7 @@ #include "SkSurface.h" #include "SkBlendModePriv.h" #include "SkColorPriv.h" - +#include "SkTextUtils.h" #include "GrContext.h" namespace skiagm { diff --git a/gn/utils.gni b/gn/utils.gni index 9dd709319d135..5a02653b49cca 100644 --- a/gn/utils.gni +++ b/gn/utils.gni @@ -63,6 +63,7 @@ skia_utils_sources = [ "$_src/utils/SkShadowTessellator.cpp", "$_src/utils/SkShadowTessellator.h", "$_src/utils/SkShadowUtils.cpp", + "$_src/utils/SkTextUtils.cpp", "$_src/utils/SkThreadUtils_pthread.cpp", "$_src/utils/SkThreadUtils_win.cpp", "$_src/utils/SkUTF.cpp", diff --git a/include/utils/SkTextUtils.h b/include/utils/SkTextUtils.h new file mode 100644 index 0000000000000..33bfd56df2c8b --- /dev/null +++ b/include/utils/SkTextUtils.h @@ -0,0 +1,31 @@ +/* + * Copyright 2018 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkTextUtils_DEFINED +#define SkTextUtils_DEFINED + +#include "SkCanvas.h" +#include "SkPaint.h" +#include "SkFont.h" +#include "SkString.h" + +class SkTextUtils { +public: + static void DrawText(SkCanvas*, const void* text, size_t size, SkScalar x, SkScalar y, + const SkPaint&, SkPaint::Align = SkPaint::kLeft_Align); + + static void DrawString(SkCanvas* canvas, const char text[], SkScalar x, SkScalar y, + const SkPaint& paint, SkPaint::Align align = SkPaint::kLeft_Align) { + DrawText(canvas, text, strlen(text), x, y, paint, align); + } + static void DrawString(SkCanvas* canvas, const SkString& str, SkScalar x, SkScalar y, + const SkPaint& paint, SkPaint::Align align = SkPaint::kLeft_Align) { + DrawText(canvas, str.c_str(), str.size(), x, y, paint, align); + } +}; + +#endif diff --git a/src/utils/SkTextUtils.cpp b/src/utils/SkTextUtils.cpp new file mode 100644 index 0000000000000..784cf7d3b1a31 --- /dev/null +++ b/src/utils/SkTextUtils.cpp @@ -0,0 +1,53 @@ +/* + * Copyright 2018 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "SkTextUtils.h" + +void SkTextUtils::DrawText(SkCanvas* canvas, const void* text, size_t size, SkScalar x, SkScalar y, + const SkPaint& origPaint, SkPaint::Align align) { + int count = origPaint.countText(text, size); + if (!count) { + return; + } + + SkPaint paint(origPaint); + SkAutoSTArray<32, uint16_t> glyphStorage; + const uint16_t* glyphs; + + if (paint.getTextEncoding() != SkPaint::kGlyphID_TextEncoding) { + glyphStorage.reset(count); + paint.textToGlyphs(text, size, glyphStorage.get()); + glyphs = glyphStorage.get(); + paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); + } else { + glyphs = static_cast(text); + } + + SkAutoSTArray<32, SkScalar> widthStorage(count); + SkScalar* widths = widthStorage.get(); + paint.getTextWidths(glyphs, count * sizeof(uint16_t), widths); + + if (align != SkPaint::kLeft_Align) { + SkScalar offset = 0; + for (int i = 0; i < count; ++i) { + offset += widths[i]; + } + if (align == SkPaint::kCenter_Align) { + offset *= 0.5f; + } + x -= offset; + } + + // Turn widths into h-positions + for (int i = 0; i < count; ++i) { + SkScalar w = widths[i]; + widths[i] = x; + x += w; + } + canvas->drawPosTextH(glyphs, count * sizeof(uint16_t), widths, y, paint); +} +