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