OLD | NEW |
(Empty) | |
| 1 /* |
| 2 * Copyright 2013 Google Inc. |
| 3 * |
| 4 * Use of this source code is governed by a BSD-style license that can be |
| 5 * found in the LICENSE file. |
| 6 */ |
| 7 |
| 8 #include "gm.h" |
| 9 |
| 10 #include "Resources.h" |
| 11 #include "SkCanvas.h" |
| 12 #include "SkGradientShader.h" |
| 13 #include "SkStream.h" |
| 14 #include "SkTextBlob.h" |
| 15 #include "SkTypeface.h" |
| 16 |
| 17 namespace skiagm { |
| 18 |
| 19 static void add_to_text_blob(SkTextBlobBuilder* builder, const char* text, const
SkPaint& origPaint, |
| 20 SkScalar x, SkScalar y) { |
| 21 SkPaint paint(origPaint); |
| 22 SkTDArray<uint16_t> glyphs; |
| 23 |
| 24 size_t len = strlen(text); |
| 25 glyphs.append(paint.textToGlyphs(text, len, NULL)); |
| 26 paint.textToGlyphs(text, len, glyphs.begin()); |
| 27 |
| 28 paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); |
| 29 const SkTextBlobBuilder::RunBuffer& run = builder->allocRun(paint, glyphs.co
unt(), x, y, |
| 30 NULL); |
| 31 memcpy(run.glyphs, glyphs.begin(), glyphs.count() * sizeof(uint16_t)); |
| 32 } |
| 33 |
| 34 static void draw_blob(SkCanvas* canvas, const SkTextBlob* blob, const SkPaint& s
kPaint, |
| 35 const SkRect& clipRect) { |
| 36 SkPaint clipHairline; |
| 37 clipHairline.setColor(SK_ColorWHITE); |
| 38 clipHairline.setStyle(SkPaint::kStroke_Style); |
| 39 |
| 40 SkPaint paint(skPaint); |
| 41 canvas->save(); |
| 42 canvas->drawRect(clipRect, clipHairline); |
| 43 paint.setAlpha(0x20); |
| 44 canvas->drawTextBlob(blob, 0, 0, paint); |
| 45 canvas->clipRect(clipRect); |
| 46 paint.setAlpha(0xFF); |
| 47 canvas->drawTextBlob(blob, 0, 0, paint); |
| 48 canvas->restore(); |
| 49 } |
| 50 |
| 51 class MixedTextBlobsGM : public GM { |
| 52 public: |
| 53 MixedTextBlobsGM() { } |
| 54 |
| 55 protected: |
| 56 void onOnceBeforeDraw() override { |
| 57 SkAutoTDelete<SkFILEStream> stream; |
| 58 SkString filename; |
| 59 #ifndef SK_BUILD_FOR_MAC |
| 60 filename = GetResourcePath("/Funkster.ttf"); |
| 61 stream.reset(new SkFILEStream(filename.c_str())); |
| 62 if (stream->isValid()) { |
| 63 fEmojiTypeface.reset(SkTypeface::CreateFromStream(stream.detach())); |
| 64 } else { |
| 65 SkDebugf("Could not find Funkster.ttf, please set --resourcePath cor
rectly.\n"); |
| 66 } |
| 67 fEmojiText = "Emoji!!!"; |
| 68 #else |
| 69 fEmojiTypeface.reset(SkTypeface::CreateFromName("Apple Color Emoji", SkT
ypeface::kNormal)); |
| 70 fEmojiText = "\xF0\x9F\x92\xB0" "\xF0\x9F\x8F\xA1" "\xF0\x9F\x8E\x85" //
💰🏡🎅 |
| 71 "\xF0\x9F\x8D\xAA" "\xF0\x9F\x8D\x95" "\xF0\x9F\x9A\x80"; /
/ 🍪🍕🚀 |
| 72 #endif |
| 73 |
| 74 filename = GetResourcePath("/ReallyBigA.ttf"); |
| 75 |
| 76 stream.reset(new SkFILEStream(filename.c_str())); |
| 77 if (stream->isValid()) { |
| 78 fReallyBigATypeface.reset(SkTypeface::CreateFromStream(stream.detach
())); |
| 79 } |
| 80 |
| 81 SkTextBlobBuilder builder; |
| 82 |
| 83 // make textblob |
| 84 // Text so large we draw as paths |
| 85 SkPaint paint; |
| 86 paint.setTextSize(384); |
| 87 const char* text = "O"; |
| 88 sk_tool_utils::set_portable_typeface(&paint); |
| 89 |
| 90 SkRect bounds; |
| 91 paint.measureText(text, strlen(text), &bounds); |
| 92 |
| 93 SkScalar yOffset = bounds.height(); |
| 94 add_to_text_blob(&builder, text, paint, 10, yOffset); |
| 95 SkScalar corruptedAx = bounds.width(); |
| 96 SkScalar corruptedAy = yOffset; |
| 97 |
| 98 const SkScalar boundsHalfWidth = bounds.width() * SK_ScalarHalf; |
| 99 const SkScalar boundsHalfHeight = bounds.height() * SK_ScalarHalf; |
| 100 |
| 101 SkScalar xOffset = boundsHalfWidth; |
| 102 yOffset = boundsHalfHeight; |
| 103 |
| 104 // LCD |
| 105 paint.setTextSize(32); |
| 106 text = "LCD!!!!!"; |
| 107 paint.setSubpixelText(true); |
| 108 paint.setLCDRenderText(true); |
| 109 paint.measureText(text, strlen(text), &bounds); |
| 110 add_to_text_blob(&builder, text, paint, xOffset - bounds.width() * 0.25f
, |
| 111 yOffset - bounds.height() * 0.5f
); |
| 112 yOffset += bounds.height(); |
| 113 |
| 114 // color emoji |
| 115 paint.setSubpixelText(false); |
| 116 paint.setLCDRenderText(false); |
| 117 paint.setTypeface(fEmojiTypeface); |
| 118 text = fEmojiText; |
| 119 paint.measureText(text, strlen(text), &bounds); |
| 120 add_to_text_blob(&builder, text, paint, xOffset - bounds.width() * 0.3f,
yOffset); |
| 121 |
| 122 // Corrupted font |
| 123 paint.setTextSize(12); |
| 124 text = "aA"; |
| 125 paint.setTypeface(fReallyBigATypeface); |
| 126 add_to_text_blob(&builder, text, paint, corruptedAx, corruptedAy); |
| 127 fBlob.reset(builder.build()); |
| 128 } |
| 129 |
| 130 SkString onShortName() override { |
| 131 return SkString("mixedtextblobs"); |
| 132 } |
| 133 |
| 134 SkISize onISize() override { |
| 135 return SkISize::Make(kWidth, kHeight); |
| 136 } |
| 137 |
| 138 void onDraw(SkCanvas* canvas) override { |
| 139 |
| 140 canvas->drawColor(SK_ColorGRAY); |
| 141 |
| 142 SkPaint paint; |
| 143 |
| 144 // setup work needed to draw text with different clips |
| 145 paint.setColor(SK_ColorBLACK); |
| 146 canvas->translate(10, 40); |
| 147 |
| 148 paint.setTextSize(40); |
| 149 |
| 150 // compute the bounds of the text and setup some clips |
| 151 SkRect bounds = fBlob->bounds(); |
| 152 |
| 153 const SkScalar boundsHalfWidth = bounds.width() * SK_ScalarHalf; |
| 154 const SkScalar boundsHalfHeight = bounds.height() * SK_ScalarHalf; |
| 155 const SkScalar boundsQuarterWidth = boundsHalfWidth * SK_ScalarHalf; |
| 156 const SkScalar boundsQuarterHeight = boundsHalfHeight * SK_ScalarHalf; |
| 157 |
| 158 SkRect upperLeftClip = SkRect::MakeXYWH(bounds.left(), bounds.top(), |
| 159 boundsHalfWidth, boundsHalfHeigh
t); |
| 160 SkRect lowerRightClip = SkRect::MakeXYWH(bounds.centerX(), bounds.center
Y(), |
| 161 boundsHalfWidth, boundsHalfHeig
ht); |
| 162 SkRect interiorClip = bounds; |
| 163 interiorClip.inset(boundsQuarterWidth, boundsQuarterHeight); |
| 164 |
| 165 const SkRect clipRects[] = { bounds, upperLeftClip, lowerRightClip, inte
riorClip}; |
| 166 |
| 167 size_t count = sizeof(clipRects) / sizeof(SkRect); |
| 168 for (size_t x = 0; x < count; ++x) { |
| 169 draw_blob(canvas, fBlob, paint, clipRects[x]); |
| 170 if (x == (count >> 1) - 1) { |
| 171 canvas->translate(SkScalarFloorToScalar(bounds.width() + SkIntTo
Scalar(25)), |
| 172 -(x * SkScalarFloorToScalar(bounds.height() + |
| 173 SkIntToScalar(25)))); |
| 174 } else { |
| 175 canvas->translate(0, SkScalarFloorToScalar(bounds.height() + SkI
ntToScalar(25))); |
| 176 } |
| 177 } |
| 178 } |
| 179 |
| 180 private: |
| 181 SkAutoTUnref<SkTypeface> fEmojiTypeface; |
| 182 SkAutoTUnref<SkTypeface> fReallyBigATypeface; |
| 183 const char* fEmojiText; |
| 184 SkAutoTUnref<const SkTextBlob> fBlob; |
| 185 |
| 186 static const int kWidth = 1250; |
| 187 static const int kHeight = 700; |
| 188 |
| 189 typedef GM INHERITED; |
| 190 }; |
| 191 |
| 192 ////////////////////////////////////////////////////////////////////////////// |
| 193 |
| 194 DEF_GM( return SkNEW(MixedTextBlobsGM); ) |
| 195 } |
OLD | NEW |