1c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry/* 2c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry * Copyright 2014 Google Inc. 3c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry * 4c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry * Use of this source code is governed by a BSD-style license that can be 5c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry * found in the LICENSE file. 6c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry */ 7c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry 8c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry#include "gm.h" 9c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry#include "SkCanvas.h" 10c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry#include "SkTypeface.h" 11c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry 12c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry/* This test tries to define the effect of using hairline strokes on text. 13c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry * Provides non-hairline images for reference and consistency checks. 14c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry * glyph_pos_(h/n)_(s/f/b) 15c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry * -> test hairline/non-hairline stroke/fill/stroke+fill. 16c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry */ 17c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistrystatic const SkScalar kTextHeight = 14.0f; 18c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistrystatic const char kText[] = "Proportional Hamburgefons #% fi"; 19c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry 20c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistrynamespace skiagm { 21c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry 22c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistryclass GlyphPosGM : public GM { 23c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistrypublic: 24c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry GlyphPosGM(SkScalar strokeWidth, SkPaint::Style strokeStyle) 25c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry : fStrokeWidth(strokeWidth) 26c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry , fStrokeStyle(strokeStyle) { 27c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry } 28c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry 29c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistryprotected: 30c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry virtual uint32_t onGetFlags() const SK_OVERRIDE { 31c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry return kSkipTiled_Flag; 32c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry } 33c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry 34c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry virtual SkString onShortName() SK_OVERRIDE { 35c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry SkString str("glyph_pos"); 36c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry if (fStrokeWidth == 0.0f) { 37c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry str.append("_h"); // h == Hairline. 38c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry } else { 39c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry str.append("_n"); // n == Normal. 40c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry } 41c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry if (fStrokeStyle == SkPaint::kStroke_Style) { 42c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry str.append("_s"); 43c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry } else if (fStrokeStyle == SkPaint::kFill_Style) { 44c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry str.append("_f"); 45c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry } else { 46c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry str.append("_b"); // b == Both. 47c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry } 48c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry return str; 49c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry } 50c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry 51c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry virtual SkISize onISize() { return SkISize::Make(800, 600); } 52c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry 53c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry virtual void onDraw(SkCanvas* canvas) SK_OVERRIDE { 54c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry if (!fProp) { 55992c7b03ef7914a18bfd78e965b0b4c99a5f5672Cary Clark fProp.reset(sk_tool_utils::create_portable_typeface("Helvetica", SkTypeface::kNormal)); 56c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry } 57c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry 58c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry // There's a black pixel at 40, 40 for reference. 59c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry canvas->drawPoint(40.0f, 40.0f, SK_ColorBLACK); 60c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry 61c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry // Two reference images. 62c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry canvas->translate(50.0f, 50.0f); 63c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry drawTestCase(canvas, 1.0f); 64c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry 65c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry canvas->translate(0.0f, 50.0f); 66c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry drawTestCase(canvas, 3.0f); 67c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry 68c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry // Uniform scaling test. 69c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry canvas->translate(0.0f, 100.0f); 70c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry canvas->save(); 71c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry canvas->scale(3.0f, 3.0f); 72c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry drawTestCase(canvas, 1.0f); 73c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry canvas->restore(); 74c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry 75c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry // Non-uniform scaling test. 76c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry canvas->translate(0.0f, 100.0f); 77c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry canvas->save(); 78c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry canvas->scale(3.0f, 6.0f); 79c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry drawTestCase(canvas, 1.0f); 80c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry canvas->restore(); 81c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry 82c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry // Skew test. 83c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry canvas->translate(0.0f, 80.0f); 84c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry canvas->save(); 85c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry canvas->scale(3.0f, 3.0f); 86c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry SkMatrix skew; 87c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry skew.setIdentity(); 88c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry skew.setSkewX(SkScalarDiv(8.0f, 89c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry 25.0f)); 90c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry skew.setSkewY(SkScalarDiv(2.0f, 91c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry 25.0f)); 92c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry canvas->concat(skew); 93c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry drawTestCase(canvas, 1.0f); 94c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry canvas->restore(); 95c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry 96c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry // Perspective test. 97c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry canvas->translate(0.0f, 80.0f); 98c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry canvas->save(); 99c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry SkMatrix perspective; 100c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry perspective.setIdentity(); 101c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry perspective.setPerspX(-SkScalarDiv(SK_Scalar1, 340.0f)); 102c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry perspective.setSkewX(SkScalarDiv(8.0f, 103c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry 25.0f)); 104c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry perspective.setSkewY(SkScalarDiv(2.0f, 105c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry 25.0f)); 106c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry 107c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry 108c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry canvas->concat(perspective); 109c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry drawTestCase(canvas, 1.0f); 110c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry canvas->restore(); 111c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry } 112c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry 113c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry void drawTestCase(SkCanvas* canvas, SkScalar textScale) { 114c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry SkPaint paint; 115c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry paint.setColor(SK_ColorBLACK); 116c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry paint.setAntiAlias(true); 117c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry paint.setTextSize(kTextHeight * textScale); 118c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry paint.setTypeface(fProp); 119c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry paint.setDevKernText(true); 120c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry paint.setStrokeWidth(fStrokeWidth); 121c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry paint.setStyle(fStrokeStyle); 122c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry 123c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry // This demonstrates that we can not measure the text if there's a device transform. The 124c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry // canvas total matrix will end up being a device transform. 125c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry bool drawRef = !(canvas->getTotalMatrix().getType() & 126c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry ~(SkMatrix::kIdentity_Mask | SkMatrix::kTranslate_Mask)); 127c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry 128c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry SkRect bounds; 129c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry if (drawRef) { 130c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry SkScalar advance = paint.measureText(kText, sizeof(kText) - 1, &bounds); 131c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry 132c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry paint.setStrokeWidth(0.0f); 133c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry paint.setStyle(SkPaint::kStroke_Style); 134c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry 135c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry // Green box is the measured text bounds. 136c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry paint.setColor(SK_ColorGREEN); 137c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry canvas->drawRect(bounds, paint); 138c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry 139c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry // Red line is the measured advance from the 0,0 of the text position. 140c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry paint.setColor(SK_ColorRED); 141c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry canvas->drawLine(0.0f, 0.0f, advance, 0.0f, paint); 142c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry } 143c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry 144c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry // Black text is the testcase, eg. the text. 145c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry paint.setColor(SK_ColorBLACK); 146c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry paint.setStrokeWidth(fStrokeWidth); 147c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry paint.setStyle(fStrokeStyle); 148c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry canvas->drawText(kText, sizeof(kText) - 1, 0.0f, 0.0f, paint); 149c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry 150c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry if (drawRef) { 151c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry SkScalar widths[sizeof(kText) - 1]; 152c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry paint.getTextWidths(kText, sizeof(kText) - 1, widths, NULL); 153c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry 154c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry paint.setStrokeWidth(0.0f); 155c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry paint.setStyle(SkPaint::kStroke_Style); 156c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry 157c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry // Magenta lines are the positions for the characters. 158c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry paint.setColor(SK_ColorMAGENTA); 159c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry SkScalar w = bounds.x(); 160c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry for (size_t i = 0; i < sizeof(kText) - 1; ++i) { 161c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry canvas->drawLine(w, 0.0f, w, 5.0f, paint); 162c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry w += widths[i]; 163c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry } 164c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry } 165c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry } 166c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry 167c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistryprivate: 168c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry SkAutoTUnref<SkTypeface> fProp; 169c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry SkScalar fStrokeWidth; 170c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry SkPaint::Style fStrokeStyle; 171c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry 172c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry typedef GM INHERITED; 173c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry}; 174c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry 175c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry////////////////////////////////////////////////////////////////////////////// 176c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry 177c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistrystatic GM* GlyphPosHairlineStrokeAndFillFactory(void*) { 178c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry return new GlyphPosGM(0.0f, SkPaint::kStrokeAndFill_Style); 179c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry} 180c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistrystatic GM* GlyphPosStrokeAndFillFactory(void*) { 181c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry return new GlyphPosGM(1.2f, SkPaint::kStrokeAndFill_Style); 182c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry} 183c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistrystatic GM* GlyphPosHairlineStrokeFactory(void*) { 184c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry return new GlyphPosGM(0.0f, SkPaint::kStroke_Style); 185c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry} 186c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistrystatic GM* GlyphPosStrokeFactory(void*) { 187c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry return new GlyphPosGM(1.2f, SkPaint::kStroke_Style); 188c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry} 189c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistrystatic GM* GlyphPosHairlineFillFactory(void*) { 190c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry return new GlyphPosGM(0.0f, SkPaint::kFill_Style); 191c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry} 192c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistrystatic GM* GlyphPosFillFactory(void*) { 193c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry return new GlyphPosGM(1.2f, SkPaint::kFill_Style); 194c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry} 195c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry 196c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistrystatic GMRegistry reg1(GlyphPosHairlineStrokeAndFillFactory); 197c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistrystatic GMRegistry reg2(GlyphPosStrokeAndFillFactory); 198c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistrystatic GMRegistry reg3(GlyphPosHairlineStrokeFactory); 199c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistrystatic GMRegistry reg4(GlyphPosStrokeFactory); 200c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistrystatic GMRegistry reg5(GlyphPosHairlineFillFactory); 201c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistrystatic GMRegistry reg6(GlyphPosFillFactory); 202c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry 203c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry 204c4b84aef1adeb68bc853f35abb85b79fa1fcaac6rmistry} 205