| /* | 
 |  * Copyright 2011 Google Inc. | 
 |  * | 
 |  * Use of this source code is governed by a BSD-style license that can be | 
 |  * found in the LICENSE file. | 
 |  */ | 
 | #include "samplecode/Sample.h" | 
 |  | 
 | #include "include/core/SkCanvas.h" | 
 | #include "include/core/SkColorFilter.h" | 
 | #include "include/core/SkColorPriv.h" | 
 | #include "include/core/SkGraphics.h" | 
 | #include "include/core/SkPath.h" | 
 | #include "include/core/SkRegion.h" | 
 | #include "include/core/SkShader.h" | 
 | #include "include/core/SkStream.h" | 
 | #include "include/core/SkTextBlob.h" | 
 | #include "include/core/SkTime.h" | 
 | #include "include/core/SkTypeface.h" | 
 | #include "include/effects/SkGradientShader.h" | 
 | #include "include/utils/SkRandom.h" | 
 | #include "modules/skshaper/include/SkShaper.h" | 
 | #include "src/core/SkOSFile.h" | 
 | #include "src/shaders/SkColorShader.h" | 
 | #include "src/utils/SkUTF.h" | 
 |  | 
 | typedef std::unique_ptr<SkShaper> (*ShaperFactory)(); | 
 |  | 
 | static const char gText[] = | 
 |     "When in the Course of human events it becomes necessary for one people " | 
 |     "to dissolve the political bands which have connected them with another " | 
 |     "and to assume among the powers of the earth, the separate and equal " | 
 |     "station to which the Laws of Nature and of Nature's God entitle them, " | 
 |     "a decent respect to the opinions of mankind requires that they should " | 
 |     "declare the causes which impel them to the separation."; | 
 |  | 
 | class TextBoxView : public Sample { | 
 |     SkString fName; | 
 | public: | 
 |     TextBoxView(ShaperFactory fact, const char suffix[]) : fShaper(fact()) { | 
 |         fName.printf("TextBox_%s", suffix); | 
 |     } | 
 |  | 
 | protected: | 
 |     SkString name() override { return fName; } | 
 |  | 
 |     void drawTest(SkCanvas* canvas, SkScalar w, SkScalar h, SkColor fg, SkColor bg) { | 
 |         SkAutoCanvasRestore acr(canvas, true); | 
 |  | 
 |         canvas->clipRect(SkRect::MakeWH(w, h)); | 
 |         canvas->drawColor(bg); | 
 |  | 
 |         SkScalar margin = 20; | 
 |  | 
 |         SkPaint paint; | 
 |         paint.setColor(fg); | 
 |  | 
 |         for (int i = 9; i < 24; i += 2) { | 
 |             SkTextBlobBuilderRunHandler builder(gText, { margin, margin }); | 
 |             SkFont srcFont(nullptr, SkIntToScalar(i)); | 
 |             srcFont.setEdging(SkFont::Edging::kSubpixelAntiAlias); | 
 |             srcFont.setSubpixel(true); | 
 |  | 
 |             const char* utf8 = gText; | 
 |             size_t utf8Bytes = sizeof(gText) - 1; | 
 |  | 
 |             std::unique_ptr<SkShaper::BiDiRunIterator> bidi( | 
 |                 SkShaper::MakeBiDiRunIterator(utf8, utf8Bytes, 0xfe)); | 
 |             if (!bidi) { | 
 |                 return; | 
 |             } | 
 |  | 
 |             std::unique_ptr<SkShaper::LanguageRunIterator> language( | 
 |                 SkShaper::MakeStdLanguageRunIterator(utf8, utf8Bytes)); | 
 |             if (!language) { | 
 |                 return; | 
 |             } | 
 |  | 
 |             SkFourByteTag undeterminedScript = SkSetFourByteTag('Z','y','y','y'); | 
 |             std::unique_ptr<SkShaper::ScriptRunIterator> script( | 
 |                 SkShaper::MakeScriptRunIterator(utf8, utf8Bytes, undeterminedScript)); | 
 |             if (!script) { | 
 |                 return; | 
 |             } | 
 |  | 
 |             std::unique_ptr<SkShaper::FontRunIterator> font( | 
 |                 SkShaper::MakeFontMgrRunIterator(utf8, utf8Bytes, srcFont, SkFontMgr::RefDefault(), | 
 |                                                  "Arial", SkFontStyle::Bold(), &*language)); | 
 |             if (!font) { | 
 |                 return; | 
 |             } | 
 |  | 
 |             fShaper->shape(utf8, utf8Bytes, *font, *bidi, *script, *language, w - margin, &builder); | 
 |             canvas->drawTextBlob(builder.makeBlob(), 0, 0, paint); | 
 |  | 
 |             canvas->translate(0, builder.endPoint().y()); | 
 |         } | 
 |     } | 
 |  | 
 |     void onDrawContent(SkCanvas* canvas) override { | 
 |         SkScalar width = this->width() / 3; | 
 |         drawTest(canvas, width, this->height(), SK_ColorBLACK, SK_ColorWHITE); | 
 |         canvas->translate(width, 0); | 
 |         drawTest(canvas, width, this->height(), SK_ColorWHITE, SK_ColorBLACK); | 
 |         canvas->translate(width, 0); | 
 |         drawTest(canvas, width, this->height()/2, SK_ColorGRAY, SK_ColorWHITE); | 
 |         canvas->translate(0, this->height()/2); | 
 |         drawTest(canvas, width, this->height()/2, SK_ColorGRAY, SK_ColorBLACK); | 
 |     } | 
 |  | 
 | private: | 
 |     std::unique_ptr<SkShaper> fShaper; | 
 |     using INHERITED = Sample; | 
 | }; | 
 |  | 
 | DEF_SAMPLE( return new TextBoxView([](){ return SkShaper::Make(); }, "default"); ); | 
 | #ifdef SK_SHAPER_CORETEXT_AVAILABLE | 
 | DEF_SAMPLE( return new TextBoxView(SkShaper::MakeCoreText, "coretext"); ); | 
 | #endif | 
 |  | 
 | class SampleShaper : public Sample { | 
 | public: | 
 |     SampleShaper() {} | 
 |  | 
 | protected: | 
 |     SkString name() override { return SkString("shaper"); } | 
 |  | 
 |     void drawTest(SkCanvas* canvas, const char str[], SkScalar size, | 
 |                   std::unique_ptr<SkShaper> shaper) { | 
 |         if (!shaper) return; | 
 |  | 
 |         SkTextBlobBuilderRunHandler builder(str, {0, 0}); | 
 |         SkFont srcFont; | 
 |         srcFont.setSize(size); | 
 |         srcFont.setEdging(SkFont::Edging::kSubpixelAntiAlias); | 
 |         srcFont.setSubpixel(true); | 
 |  | 
 |         size_t len = strlen(str); | 
 |  | 
 |         std::unique_ptr<SkShaper::BiDiRunIterator> bidi( | 
 |             SkShaper::MakeBiDiRunIterator(str, len, 0xfe)); | 
 |         if (!bidi) { | 
 |             return; | 
 |         } | 
 |  | 
 |         std::unique_ptr<SkShaper::LanguageRunIterator> language( | 
 |             SkShaper::MakeStdLanguageRunIterator(str, len)); | 
 |         if (!language) { | 
 |             return; | 
 |         } | 
 |  | 
 |         SkFourByteTag undeterminedScript = SkSetFourByteTag('Z','y','y','y'); | 
 |         std::unique_ptr<SkShaper::ScriptRunIterator> script( | 
 |             SkShaper::MakeScriptRunIterator(str, len, undeterminedScript)); | 
 |         if (!script) { | 
 |             return; | 
 |         } | 
 |  | 
 |         std::unique_ptr<SkShaper::FontRunIterator> font( | 
 |             SkShaper::MakeFontMgrRunIterator(str, len, srcFont, SkFontMgr::RefDefault(), | 
 |                                              "Arial", SkFontStyle::Bold(), &*language)); | 
 |         if (!font) { | 
 |             return; | 
 |         } | 
 |  | 
 |         shaper->shape(str, len, *font, *bidi, *script, *language, 2000, &builder); | 
 |  | 
 |         canvas->drawTextBlob(builder.makeBlob(), 0, 0, SkPaint()); | 
 |     } | 
 |  | 
 |     void onDrawContent(SkCanvas* canvas) override { | 
 |         canvas->translate(10, 30); | 
 |  | 
 |         const char text[] = "world"; | 
 |  | 
 |         for (SkScalar size = 30; size <= 30; size += 10) { | 
 |             this->drawTest(canvas, text, size, SkShaper::Make()); | 
 |             canvas->translate(0, size + 5); | 
 |             #ifdef SK_SHAPER_CORETEXT_AVAILABLE | 
 |             this->drawTest(canvas, text, size, SkShaper::MakeCoreText()); | 
 |             #endif | 
 |             canvas->translate(0, size*2); | 
 |         } | 
 |     } | 
 |  | 
 | private: | 
 |     using INHERITED = Sample; | 
 | }; | 
 | DEF_SAMPLE( return new SampleShaper; ); |