1/* 2 * Copyright 2017 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 "Resources.h" 9#include "SampleCode.h" 10#include "sk_tool_utils.h" 11 12#include "SkCanvas.h" 13#include "SkFontMgr.h" 14#include "SkRandom.h" 15#include "SkTypeface.h" 16#include "SkTextBlob.h" 17 18#if SK_SUPPORT_GPU 19#include "GrContext.h" 20#endif 21 22static void make_paint(SkPaint* paint, sk_sp<SkTypeface> typeface) { 23 static const int kTextSize = 56; 24 25 paint->setAntiAlias(true); 26 paint->setColor(0xDE000000); 27 paint->setTypeface(typeface); 28 paint->setTextSize(kTextSize); 29 paint->setTextEncoding(SkPaint::kUTF32_TextEncoding); 30} 31 32static sk_sp<SkTypeface> chinese_typeface() { 33#ifdef SK_BUILD_FOR_ANDROID 34 return MakeResourceAsTypeface("fonts/NotoSansCJK-Regular.ttc"); 35#elif defined(SK_BUILD_FOR_WIN) 36 return SkTypeface::MakeFromName("SimSun", SkFontStyle()); 37#elif defined(SK_BUILD_FOR_MAC) 38 return SkTypeface::MakeFromName("Hiragino Sans GB W3", SkFontStyle()); 39#elif defined(SK_BUILD_FOR_IOS) 40 return SkTypeface::MakeFromName("Hiragino Sans GB W3", SkFontStyle()); 41#elif defined(SK_BUILD_FOR_UNIX) 42 return SkTypeface::MakeFromName("Noto Sans CJK SC", SkFontStyle()); 43#else 44 return nullptr; 45#endif 46} 47 48class ChineseFlingView : public SampleView { 49public: 50 ChineseFlingView() : fBlobs(kNumBlobs) {} 51 52protected: 53 bool onQuery(SkEvent* evt) override { 54 if (SampleCode::TitleQ(*evt)) { 55 SampleCode::TitleR(evt, "chinese-fling"); 56 return true; 57 } 58 return this->INHERITED::onQuery(evt); 59 } 60 61 void onDrawContent(SkCanvas* canvas) override { 62 if (!fInitialized) { 63 this->init(); 64 fInitialized = true; 65 } 66 67 canvas->clear(0xFFDDDDDD); 68 69 SkPaint paint; 70 make_paint(&paint, fTypeface); 71 72 // draw a consistent run of the 'words' - one word per line 73 int index = fIndex; 74 for (SkScalar y = 0.0f; y < 1024.0f; ) { 75 76 y += -fMetrics.fAscent; 77 canvas->drawTextBlob(fBlobs[index], 0, y, paint); 78 79 y += fMetrics.fDescent + fMetrics.fLeading; 80 ++index; 81 index %= fBlobs.count(); 82 } 83 // now "fling" a random amount 84 fIndex += fRand.nextRangeU(5, 20); 85 fIndex %= fBlobs.count(); 86 } 87 88private: 89 static constexpr auto kNumBlobs = 200; 90 static constexpr auto kWordLength = 16; 91 92 void init() { 93 fTypeface = chinese_typeface(); 94 95 SkPaint paint; 96 make_paint(&paint, fTypeface); 97 98 paint.getFontMetrics(&fMetrics); 99 100 SkUnichar glyphs[kWordLength]; 101 for (int32_t i = 0; i < kNumBlobs; ++i) { 102 this->createRandomWord(glyphs); 103 104 SkTextBlobBuilder builder; 105 sk_tool_utils::add_to_text_blob_w_len(&builder, (const char*) glyphs, kWordLength*4, 106 paint, 0, 0); 107 108 fBlobs.emplace_back(builder.make()); 109 } 110 111 fIndex = 0; 112 } 113 114 // Construct a random kWordLength character 'word' drawing from the full Chinese set 115 void createRandomWord(SkUnichar glyphs[kWordLength]) { 116 for (int i = 0; i < kWordLength; ++i) { 117 glyphs[i] = fRand.nextRangeU(0x4F00, 0x9FA0); 118 } 119 } 120 121 bool fInitialized = false; 122 sk_sp<SkTypeface> fTypeface; 123 SkPaint::FontMetrics fMetrics; 124 SkTArray<sk_sp<SkTextBlob>> fBlobs; 125 SkRandom fRand; 126 int fIndex; 127 128 typedef SkView INHERITED; 129}; 130 131class ChineseZoomView : public SampleView { 132public: 133 ChineseZoomView() : fBlobs(kNumBlobs), fScale(15.0f), fTranslate(0.0f) {} 134 135protected: 136 bool onQuery(SkEvent* evt) override { 137 if (SampleCode::TitleQ(*evt)) { 138 SampleCode::TitleR(evt, "chinese-zoom"); 139 return true; 140 } 141 SkUnichar uni; 142 if (SampleCode::CharQ(*evt, &uni)) { 143 if ('>' == uni) { 144 fScale += 0.125f; 145 return true; 146 } 147 if ('<' == uni) { 148 fScale -= 0.125f; 149 return true; 150 } 151 } 152 return this->INHERITED::onQuery(evt); 153 } 154 155 void onDrawContent(SkCanvas* canvas) override { 156 bool afterFirstFrame = fInitialized; 157 if (!fInitialized) { 158 this->init(); 159 fInitialized = true; 160 } 161 162 canvas->clear(0xFFDDDDDD); 163 164 SkPaint paint; 165 paint.setAntiAlias(true); 166 paint.setColor(0xDE000000); 167 paint.setTypeface(fTypeface); 168 paint.setTextSize(11); 169 paint.setTextEncoding(SkPaint::kUTF32_TextEncoding); 170 171 if (afterFirstFrame) { 172#if SK_SUPPORT_GPU 173 GrContext* grContext = canvas->getGrContext(); 174 if (grContext) { 175 sk_sp<SkImage> image = 176 grContext->getFontAtlasImage_ForTesting(GrMaskFormat::kA8_GrMaskFormat, 0); 177 canvas->drawImageRect(image, 178 SkRect::MakeXYWH(10.0f, 10.0f, 512.0f, 512.0), &paint); 179 image = grContext->getFontAtlasImage_ForTesting(GrMaskFormat::kA8_GrMaskFormat, 1); 180 canvas->drawImageRect(image, 181 SkRect::MakeXYWH(522.0f, 10.0f, 512.f, 512.0f), &paint); 182 image = grContext->getFontAtlasImage_ForTesting(GrMaskFormat::kA8_GrMaskFormat, 2); 183 canvas->drawImageRect(image, 184 SkRect::MakeXYWH(10.0f, 522.0f, 512.0f, 512.0f), &paint); 185 image = grContext->getFontAtlasImage_ForTesting(GrMaskFormat::kA8_GrMaskFormat, 3); 186 canvas->drawImageRect(image, 187 SkRect::MakeXYWH(522.0f, 522.0f, 512.0f, 512.0f), &paint); 188 } 189#endif 190 } 191 192 canvas->scale(fScale, fScale); 193 canvas->translate(0, fTranslate); 194 fTranslate -= 0.5f; 195 196 // draw a consistent run of the 'words' - one word per line 197 SkScalar y = 0; 198 for (int index = 0; index < kNumBlobs; ++index) { 199 y += -fMetrics.fAscent; 200 canvas->drawTextBlob(fBlobs[index], 0, y, paint); 201 202 y += 3*(fMetrics.fDescent - fMetrics.fAscent + fMetrics.fLeading); 203 } 204 } 205 206private: 207 static constexpr auto kNumBlobs = 8; 208 static constexpr auto kParagraphLength = 175; 209 210 void init() { 211 fTypeface = chinese_typeface(); 212 213 SkPaint paint; 214 paint.setAntiAlias(true); 215 paint.setColor(0xDE000000); 216 paint.setTypeface(fTypeface); 217 paint.setTextSize(11); 218 paint.setTextEncoding(SkPaint::kUTF32_TextEncoding); 219 220 paint.getFontMetrics(&fMetrics); 221 222 SkUnichar glyphs[45]; 223 for (int32_t i = 0; i < kNumBlobs; ++i) { 224 SkTextBlobBuilder builder; 225 auto paragraphLength = kParagraphLength; 226 SkScalar y = 0; 227 while (paragraphLength - 45 > 0) { 228 auto currentLineLength = SkTMin(45, paragraphLength - 45); 229 this->createRandomLine(glyphs, currentLineLength); 230 231 sk_tool_utils::add_to_text_blob_w_len(&builder, (const char*) glyphs, 232 currentLineLength*4, paint, 0, y); 233 y += fMetrics.fDescent - fMetrics.fAscent + fMetrics.fLeading; 234 paragraphLength -= 45; 235 } 236 fBlobs.emplace_back(builder.make()); 237 } 238 239 fIndex = 0; 240 } 241 242 // Construct a random kWordLength character 'word' drawing from the full Chinese set 243 void createRandomLine(SkUnichar glyphs[45], int lineLength) { 244 for (auto i = 0; i < lineLength; ++i) { 245 glyphs[i] = fRand.nextRangeU(0x4F00, 0x9FA0); 246 } 247 } 248 249 bool fInitialized = false; 250 sk_sp<SkTypeface> fTypeface; 251 SkPaint::FontMetrics fMetrics; 252 SkTArray<sk_sp<SkTextBlob>> fBlobs; 253 SkRandom fRand; 254 SkScalar fScale; 255 SkScalar fTranslate; 256 int fIndex; 257 258 typedef SkView INHERITED; 259}; 260 261////////////////////////////////////////////////////////////////////////////// 262 263static SkView* FlingFactory() { return new ChineseFlingView; } 264static SkViewRegister regFling(FlingFactory); 265 266static SkView* ZoomFactory() { return new ChineseZoomView; } 267static SkViewRegister regZoom(ZoomFactory); 268