1 /*
2  * Copyright 2014 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 #include "sk_tool_utils.h"
10 #include "SkCanvas.h"
11 #include "SkTypeface.h"
12 
13 /* This test tries to define the effect of using hairline strokes on text.
14  * Provides non-hairline images for reference and consistency checks.
15  * glyph_pos_(h/n)_(s/f/b)
16  *   -> test hairline/non-hairline stroke/fill/stroke+fill.
17  */
18 constexpr SkScalar kTextHeight = 14.0f;
19 constexpr char kText[] = "Proportional Hamburgefons #% fi";
20 
21 static void drawTestCase(SkCanvas* canvas,
22                          SkScalar textScale,
23                          SkScalar strokeWidth,
24                          SkPaint::Style strokeStyle);
25 
26 static void draw_gm(SkCanvas* canvas,
27                     SkScalar strokeWidth,
28                     SkPaint::Style strokeStyle) {
29         // There's a black pixel at 40, 40 for reference.
30     canvas->drawPoint(40, 40, SkPaint());
31 
32     // Two reference images.
33     canvas->translate(50.0f, 50.0f);
34     drawTestCase(canvas, 1.0f, strokeWidth, strokeStyle);
35 
36     canvas->translate(0.0f, 50.0f);
37     drawTestCase(canvas, 3.0f, strokeWidth, strokeStyle);
38 
39     // Uniform scaling test.
40     canvas->translate(0.0f, 100.0f);
41     canvas->save();
42     canvas->scale(3.0f, 3.0f);
43     drawTestCase(canvas, 1.0f, strokeWidth, strokeStyle);
44     canvas->restore();
45 
46     // Non-uniform scaling test.
47     canvas->translate(0.0f, 100.0f);
48     canvas->save();
49     canvas->scale(3.0f, 6.0f);
50     drawTestCase(canvas, 1.0f, strokeWidth, strokeStyle);
51     canvas->restore();
52 
53     // Skew test.
54     canvas->translate(0.0f, 80.0f);
55     canvas->save();
56     canvas->scale(3.0f, 3.0f);
57     SkMatrix skew;
58     skew.setIdentity();
59     skew.setSkewX(8.0f / 25.0f);
60     skew.setSkewY(2.0f / 25.0f);
61     canvas->concat(skew);
62     drawTestCase(canvas, 1.0f, strokeWidth, strokeStyle);
63     canvas->restore();
64 
65     // Perspective test.
66     canvas->translate(0.0f, 80.0f);
67     canvas->save();
68     SkMatrix perspective;
69     perspective.setIdentity();
70     perspective.setPerspX(-SkScalarInvert(340));
71     perspective.setSkewX(8.0f / 25.0f);
72     perspective.setSkewY(2.0f / 25.0f);
73 
74     canvas->concat(perspective);
75     drawTestCase(canvas, 1.0f, strokeWidth, strokeStyle);
76     canvas->restore();
77 }
78 
79 static void drawTestCase(SkCanvas* canvas,
80                          SkScalar textScale,
81                          SkScalar strokeWidth,
82                          SkPaint::Style strokeStyle) {
83         SkPaint paint;
84         paint.setColor(SK_ColorBLACK);
85         paint.setAntiAlias(true);
86         paint.setTextSize(kTextHeight * textScale);
87         sk_tool_utils::set_portable_typeface(&paint);
88         paint.setStrokeWidth(strokeWidth);
89         paint.setStyle(strokeStyle);
90 
91         // This demonstrates that we can not measure the text if
92         // there's a device transform. The canvas total matrix will
93         // end up being a device transform.
94         bool drawRef = !(canvas->getTotalMatrix().getType() &
95                          ~(SkMatrix::kIdentity_Mask | SkMatrix::kTranslate_Mask));
96 
97         SkRect bounds;
98         if (drawRef) {
99             SkScalar advance = paint.measureText(kText, sizeof(kText) - 1, &bounds);
100 
101             paint.setStrokeWidth(0.0f);
102             paint.setStyle(SkPaint::kStroke_Style);
103 
104             // Green box is the measured text bounds.
105             paint.setColor(SK_ColorGREEN);
106             canvas->drawRect(bounds, paint);
107 
108             // Red line is the measured advance from the 0,0 of the text position.
109             paint.setColor(SK_ColorRED);
110             canvas->drawLine(0.0f, 0.0f, advance, 0.0f, paint);
111         }
112 
113         // Black text is the testcase, eg. the text.
114         paint.setColor(SK_ColorBLACK);
115         paint.setStrokeWidth(strokeWidth);
116         paint.setStyle(strokeStyle);
117         canvas->drawText(kText, sizeof(kText) - 1, 0.0f, 0.0f, paint);
118 
119         if (drawRef) {
120             SkScalar widths[sizeof(kText) - 1];
121             paint.getTextWidths(kText, sizeof(kText) - 1, widths, nullptr);
122 
123             paint.setStrokeWidth(0.0f);
124             paint.setStyle(SkPaint::kStroke_Style);
125 
126             // Magenta lines are the positions for the characters.
127             paint.setColor(SK_ColorMAGENTA);
128             SkScalar w = bounds.x();
129             for (size_t i = 0; i < sizeof(kText) - 1; ++i) {
130                 canvas->drawLine(w, 0.0f, w, 5.0f, paint);
131                 w += widths[i];
132             }
133         }
134 }
135 
136 DEF_SIMPLE_GM(glyph_pos_h_b, c, 800, 600) {
137     draw_gm(c, 0.0f, SkPaint::kStrokeAndFill_Style);
138 }
139 DEF_SIMPLE_GM(glyph_pos_n_b, c, 800, 600) {
140     draw_gm(c, 1.2f, SkPaint::kStrokeAndFill_Style);
141 }
142 DEF_SIMPLE_GM(glyph_pos_h_s, c, 800, 600) {
143     draw_gm(c, 0.0f, SkPaint::kStroke_Style);
144 }
145 DEF_SIMPLE_GM(glyph_pos_n_s, c, 800, 600) {
146     draw_gm(c, 1.2f, SkPaint::kStroke_Style);
147 }
148 DEF_SIMPLE_GM(glyph_pos_h_f, c, 800, 600) {
149     draw_gm(c, 0.0f, SkPaint::kFill_Style);
150 }
151 DEF_SIMPLE_GM(glyph_pos_n_f, c, 800, 600) {
152     draw_gm(c, 1.2f, SkPaint::kFill_Style);
153 }
154