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 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 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