xref: /aosp_15_r20/external/skia/gm/mac_aa_explorer.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1 /*
2  * Copyright 2019 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/gm.h"
9 #include "include/core/SkCanvas.h"
10 #include "include/core/SkColor.h"
11 #include "include/core/SkFont.h"
12 #include "include/core/SkFontStyle.h"
13 #include "include/core/SkFontTypes.h"
14 #include "include/core/SkPaint.h"
15 #include "include/core/SkScalar.h"
16 #include "include/core/SkTypeface.h"
17 #include "include/core/SkTypes.h"
18 #include "tools/fonts/FontToolUtils.h"
19 
20 #include <string.h>
21 #include <initializer_list>
22 
23 #ifdef SK_BUILD_FOR_MAC
24 
25 #include "include/core/SkSurface.h"
26 
27 #import <ApplicationServices/ApplicationServices.h>
28 
std_cg_setup(CGContextRef ctx)29 static void std_cg_setup(CGContextRef ctx) {
30     CGContextSetAllowsFontSubpixelQuantization(ctx, false);
31     CGContextSetShouldSubpixelQuantizeFonts(ctx, false);
32 
33     // Because CG always draws from the horizontal baseline,
34     // if there is a non-integral translation from the horizontal origin to the vertical origin,
35     // then CG cannot draw the glyph in the correct location without subpixel positioning.
36     CGContextSetAllowsFontSubpixelPositioning(ctx, true);
37     CGContextSetShouldSubpixelPositionFonts(ctx, true);
38 
39     CGContextSetAllowsFontSmoothing(ctx, true);
40     CGContextSetShouldAntialias(ctx, true);
41 
42     CGContextSetTextDrawingMode(ctx, kCGTextFill);
43 
44     // Draw black on white to create mask. (Special path exists to speed this up in CG.)
45     CGContextSetGrayFillColor(ctx, 0.0f, 1.0f);
46 }
47 
make_cg_ctx(const SkPixmap & pm)48 static CGContextRef make_cg_ctx(const SkPixmap& pm) {
49     CGBitmapInfo info;
50     CGColorSpaceRef cs;
51 
52     switch (pm.colorType()) {
53         case kRGBA_8888_SkColorType:
54             info = kCGBitmapByteOrder32Host | (CGBitmapInfo)kCGImageAlphaNoneSkipFirst;
55             cs = CGColorSpaceCreateDeviceRGB();
56             break;
57         case kGray_8_SkColorType:
58             info = kCGImageAlphaNone;
59             cs = CGColorSpaceCreateDeviceGray();
60             break;
61         case kAlpha_8_SkColorType:
62             info = kCGImageAlphaOnly;
63             cs = nullptr;
64             break;
65         default:
66             return nullptr;
67     }
68     auto ctx = CGBitmapContextCreate(pm.writable_addr(), pm.width(), pm.height(), 8, pm.rowBytes(),
69                                      cs, info);
70     std_cg_setup(ctx);
71     return ctx;
72 }
73 
test_mac_fonts(SkCanvas * canvas,SkScalar size,SkScalar xpos)74 static void test_mac_fonts(SkCanvas* canvas, SkScalar size, SkScalar xpos) {
75     int w = 32;
76     int h = 32;
77 
78     canvas->scale(10, 10);
79     SkScalar y = 1;
80 
81     for (SkColorType ct : {kRGBA_8888_SkColorType, kGray_8_SkColorType, kAlpha_8_SkColorType}) {
82         SkImageInfo ii = SkImageInfo::Make(w, h, ct, kPremul_SkAlphaType);
83         auto surf = SkSurfaces::Raster(ii);
84         SkPixmap pm;
85         surf->peekPixels(&pm);
86         CGContextRef ctx = make_cg_ctx(pm);
87         CGContextSelectFont(ctx, "Times", size, kCGEncodingMacRoman);
88 
89         SkScalar x = 1;
90         for (bool smooth : {false, true}) {
91             surf->getCanvas()->clear(ct == kAlpha_8_SkColorType ? 0 : 0xFFFFFFFF);
92             CGContextSetShouldSmoothFonts(ctx, smooth);
93             CGContextShowTextAtPoint(ctx, 2 + xpos, 2, "A", 1);
94 
95             surf->draw(canvas, x, y);
96             x += pm.width();
97         }
98         y += pm.height();
99     }
100 }
101 
102 class MacAAFontsGM : public skiagm::GM {
103     SkScalar fSize = 16;
104     SkScalar fXPos = 0;
105 
106 public:
MacAAFontsGM()107     MacAAFontsGM() {}
~MacAAFontsGM()108     ~MacAAFontsGM() override {}
109 
110 protected:
onDraw(SkCanvas * canvas,SkString * errorMsg)111     DrawResult onDraw(SkCanvas* canvas, SkString* errorMsg) override {
112         test_mac_fonts(canvas, fSize, fXPos);
113 
114         return DrawResult::kOk;
115     }
116 
getISize()117     SkISize getISize() override { return {1024, 768}; }
118 
getName() const119     SkString getName() const override { return SkString("macaatest"); }
120 
onChar(SkUnichar uni)121     bool onChar(SkUnichar uni) override {
122         switch (uni) {
123             case 'i': fSize += 1; return true;
124             case 'k': fSize -= 1; return true;
125             case 'j': fXPos -= 1.0f/16; return true;
126             case 'l': fXPos += 1.0f/16; return true;
127             default: break;
128         }
129         return false;
130     }
131 };
132 DEF_GM(return new MacAAFontsGM;)
133 
134 #endif
135 
136 DEF_SIMPLE_GM(macaa_colors, canvas, 800, 500) {
137     const SkColor GRAY = 0xFF808080;
138     const SkColor colors[] = {
139         SK_ColorBLACK, SK_ColorWHITE,
140         SK_ColorBLACK, GRAY,
141         SK_ColorWHITE, SK_ColorBLACK,
142         SK_ColorWHITE, GRAY,
143     };
144     const SkScalar sizes[] = {10, 12, 15, 18, 24};
145 
146     const SkScalar width = 200;
147     const SkScalar height = 500;
148     const char str[] = "Hamburgefons";
149     const size_t len = strlen(str);
150 
151     sk_sp<SkTypeface> face = ToolUtils::CreateTestTypeface("Times", SkFontStyle());
152     if (!face) {
153         face = ToolUtils::DefaultPortableTypeface();
154     }
155     SkFont font(face, 12);
156 
157     for (size_t i = 0; i < std::size(colors); i += 2) {
158         canvas->save();
159 
160         SkPaint paint;
161         paint.setColor(colors[i+1]);
162         canvas->drawRect({0, 0, width, height}, paint);
163         paint.setColor(colors[i]);
164 
165         SkScalar y = 10;
166         SkScalar x = 10;
167         for (SkScalar ps : sizes) {
168             font.setSize(ps);
169             for (bool lcd : {false, true}) {
170                 font.setEdging(lcd ? SkFont::Edging::kSubpixelAntiAlias
171                                    : SkFont::Edging::kAntiAlias);
172                 for (auto h : {SkFontHinting::kNone, SkFontHinting::kNormal}) {
173                     font.setHinting(h);
174 
175                     y += font.getSpacing() + 2;
176                     canvas->drawSimpleText(str, len, SkTextEncoding::kUTF8, x, y, font, paint);
177                 }
178             }
179             y += 8;
180         }
181         canvas->restore();
182         canvas->translate(width, 0);
183     }
184 }
185