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(1.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 if (!fInitialized) { 157 this->init(); 158 fInitialized = true; 159 } 160 161 canvas->clear(0xFFDDDDDD); 162 163 SkPaint paint; 164 paint.setAntiAlias(true); 165 paint.setColor(0xDE000000); 166 paint.setTypeface(fTypeface); 167 paint.setTextSize(11); 168 paint.setTextEncoding(SkPaint::kUTF32_TextEncoding); 169 170#if SK_SUPPORT_GPU 171 GrContext* grContext = canvas->getGrContext(); 172 if (grContext) { 173 sk_sp<SkImage> image = 174 grContext->getFontAtlasImage_ForTesting(GrMaskFormat::kA8_GrMaskFormat, 0); 175 canvas->drawImageRect(image, 176 SkRect::MakeXYWH(512.0f, 10.0f, 512.0f, 512.0), &paint); 177 image = grContext->getFontAtlasImage_ForTesting(GrMaskFormat::kA8_GrMaskFormat, 1); 178 canvas->drawImageRect(image, 179 SkRect::MakeXYWH(1024.0f, 10.0f, 512.f, 512.0f), &paint); 180 image = grContext->getFontAtlasImage_ForTesting(GrMaskFormat::kA8_GrMaskFormat, 2); 181 canvas->drawImageRect(image, 182 SkRect::MakeXYWH(512.0f, 522.0f, 512.0f, 512.0f), &paint); 183 image = grContext->getFontAtlasImage_ForTesting(GrMaskFormat::kA8_GrMaskFormat, 3); 184 canvas->drawImageRect(image, 185 SkRect::MakeXYWH(1024.0f, 522.0f, 512.0f, 512.0f), &paint); 186 } 187#endif 188 189 canvas->scale(fScale, fScale); 190 191 // draw a consistent run of the 'words' - one word per line 192 SkScalar y = 0; 193 for (int index = 0; index < kNumBlobs; ++index) { 194 y += -fMetrics.fAscent; 195 canvas->drawTextBlob(fBlobs[index], 0, y, paint); 196 197 y += 3*(fMetrics.fDescent - fMetrics.fAscent + fMetrics.fLeading); 198 } 199 } 200 201private: 202 static constexpr auto kNumBlobs = 8; 203 static constexpr auto kParagraphLength = 175; 204 205 void init() { 206 fTypeface = chinese_typeface(); 207 208 SkPaint paint; 209 paint.setAntiAlias(true); 210 paint.setColor(0xDE000000); 211 paint.setTypeface(fTypeface); 212 paint.setTextSize(11); 213 paint.setTextEncoding(SkPaint::kUTF32_TextEncoding); 214 215 paint.getFontMetrics(&fMetrics); 216 217 SkUnichar glyphs[45]; 218 for (int32_t i = 0; i < kNumBlobs; ++i) { 219 SkTextBlobBuilder builder; 220 auto paragraphLength = kParagraphLength; 221 SkScalar y = 0; 222 while (paragraphLength - 45 > 0) { 223 auto currentLineLength = SkTMin(45, paragraphLength - 45); 224 this->createRandomLine(glyphs, currentLineLength); 225 226 sk_tool_utils::add_to_text_blob_w_len(&builder, (const char*) glyphs, 227 currentLineLength*4, paint, 0, y); 228 y += fMetrics.fDescent - fMetrics.fAscent + fMetrics.fLeading; 229 paragraphLength -= 45; 230 } 231 fBlobs.emplace_back(builder.make()); 232 } 233 234 fIndex = 0; 235 } 236 237 // Construct a random kWordLength character 'word' drawing from the full Chinese set 238 void createRandomLine(SkUnichar glyphs[45], int lineLength) { 239 for (auto i = 0; i < lineLength; ++i) { 240 glyphs[i] = fRand.nextRangeU(0x4F00, 0x9FA0); 241 } 242 } 243 244 bool fInitialized = false; 245 sk_sp<SkTypeface> fTypeface; 246 SkPaint::FontMetrics fMetrics; 247 SkTArray<sk_sp<SkTextBlob>> fBlobs; 248 SkRandom fRand; 249 SkScalar fScale; 250 int fIndex; 251 252 typedef SkView INHERITED; 253}; 254 255////////////////////////////////////////////////////////////////////////////// 256 257static SkView* FlingFactory() { return new ChineseFlingView; } 258static SkViewRegister regFling(FlingFactory); 259 260static SkView* ZoomFactory() { return new ChineseZoomView; } 261static SkViewRegister regZoom(ZoomFactory); 262