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