aboutsummaryrefslogtreecommitdiffhomepage
path: root/gm
diff options
context:
space:
mode:
authorGravatar kkinnunen <kkinnunen@nvidia.com>2014-06-22 22:18:14 -0700
committerGravatar Commit bot <commit-bot@chromium.org>2014-06-22 22:18:14 -0700
commit196af738027c5e18c3eb792dbcaf90ef27821793 (patch)
treefed1ded62e61a247554117f3722429dcc63f978d /gm
parent1c4d5784f9957143e86a7455e64ea6ac9661bb9e (diff)
Fix SkPaint::measureText for stroked hairline text
SkPaint::measureText and text drawing used different criteria for determining whether text should be drawn as paths or not. Adds tests glyph_pos_(h/n)_(s/f/b) to test the text rendering and the glyph positioning in the rendering. Mainly added in order to define what is the expected text rendering when hairline stroke is used with various transform options. The testcase also tries to note or highlight the fact that SkPaint::measureText is not expected to produce intuitively matching results when compared to a rendering, if the rendering is done so that the device ends up having a device transform. This fixes the glyph_pos_h_s (hairline, stroked) test-case. Ignore shadertext2_pdf-poppler.png gm on Test-Ubuntu13.10-ShuttleA-NoGPU-x86_64-Debug temporarily, as that fails. R=jvanverth@google.com, reed@google.com Author: kkinnunen@nvidia.com Review URL: https://codereview.chromium.org/335603003
Diffstat (limited to 'gm')
-rw-r--r--gm/glyph_pos.cpp204
1 files changed, 204 insertions, 0 deletions
diff --git a/gm/glyph_pos.cpp b/gm/glyph_pos.cpp
new file mode 100644
index 0000000000..b0451016ac
--- /dev/null
+++ b/gm/glyph_pos.cpp
@@ -0,0 +1,204 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "gm.h"
+#include "SkCanvas.h"
+#include "SkTypeface.h"
+
+/* This test tries to define the effect of using hairline strokes on text.
+ * Provides non-hairline images for reference and consistency checks.
+ * glyph_pos_(h/n)_(s/f/b)
+ * -> test hairline/non-hairline stroke/fill/stroke+fill.
+ */
+static const SkScalar kTextHeight = 14.0f;
+static const char kText[] = "Proportional Hamburgefons #% fi";
+
+namespace skiagm {
+
+class GlyphPosGM : public GM {
+public:
+ GlyphPosGM(SkScalar strokeWidth, SkPaint::Style strokeStyle)
+ : fStrokeWidth(strokeWidth)
+ , fStrokeStyle(strokeStyle) {
+ }
+
+protected:
+ virtual uint32_t onGetFlags() const SK_OVERRIDE {
+ return kSkipTiled_Flag;
+ }
+
+ virtual SkString onShortName() SK_OVERRIDE {
+ SkString str("glyph_pos");
+ if (fStrokeWidth == 0.0f) {
+ str.append("_h"); // h == Hairline.
+ } else {
+ str.append("_n"); // n == Normal.
+ }
+ if (fStrokeStyle == SkPaint::kStroke_Style) {
+ str.append("_s");
+ } else if (fStrokeStyle == SkPaint::kFill_Style) {
+ str.append("_f");
+ } else {
+ str.append("_b"); // b == Both.
+ }
+ return str;
+ }
+
+ virtual SkISize onISize() { return SkISize::Make(800, 600); }
+
+ virtual void onDraw(SkCanvas* canvas) SK_OVERRIDE {
+ if (!fProp) {
+ fProp.reset(SkTypeface::CreateFromName("Helvetica", SkTypeface::kNormal));
+ }
+
+ // There's a black pixel at 40, 40 for reference.
+ canvas->drawPoint(40.0f, 40.0f, SK_ColorBLACK);
+
+ // Two reference images.
+ canvas->translate(50.0f, 50.0f);
+ drawTestCase(canvas, 1.0f);
+
+ canvas->translate(0.0f, 50.0f);
+ drawTestCase(canvas, 3.0f);
+
+ // Uniform scaling test.
+ canvas->translate(0.0f, 100.0f);
+ canvas->save();
+ canvas->scale(3.0f, 3.0f);
+ drawTestCase(canvas, 1.0f);
+ canvas->restore();
+
+ // Non-uniform scaling test.
+ canvas->translate(0.0f, 100.0f);
+ canvas->save();
+ canvas->scale(3.0f, 6.0f);
+ drawTestCase(canvas, 1.0f);
+ canvas->restore();
+
+ // Skew test.
+ canvas->translate(0.0f, 80.0f);
+ canvas->save();
+ canvas->scale(3.0f, 3.0f);
+ SkMatrix skew;
+ skew.setIdentity();
+ skew.setSkewX(SkScalarDiv(8.0f,
+ 25.0f));
+ skew.setSkewY(SkScalarDiv(2.0f,
+ 25.0f));
+ canvas->concat(skew);
+ drawTestCase(canvas, 1.0f);
+ canvas->restore();
+
+ // Perspective test.
+ canvas->translate(0.0f, 80.0f);
+ canvas->save();
+ SkMatrix perspective;
+ perspective.setIdentity();
+ perspective.setPerspX(-SkScalarDiv(SK_Scalar1, 340.0f));
+ perspective.setSkewX(SkScalarDiv(8.0f,
+ 25.0f));
+ perspective.setSkewY(SkScalarDiv(2.0f,
+ 25.0f));
+
+
+ canvas->concat(perspective);
+ drawTestCase(canvas, 1.0f);
+ canvas->restore();
+ }
+
+ void drawTestCase(SkCanvas* canvas, SkScalar textScale) {
+ SkPaint paint;
+ paint.setColor(SK_ColorBLACK);
+ paint.setAntiAlias(true);
+ paint.setTextSize(kTextHeight * textScale);
+ paint.setTypeface(fProp);
+ paint.setDevKernText(true);
+ paint.setStrokeWidth(fStrokeWidth);
+ paint.setStyle(fStrokeStyle);
+
+ // This demonstrates that we can not measure the text if there's a device transform. The
+ // canvas total matrix will end up being a device transform.
+ bool drawRef = !(canvas->getTotalMatrix().getType() &
+ ~(SkMatrix::kIdentity_Mask | SkMatrix::kTranslate_Mask));
+
+ SkRect bounds;
+ if (drawRef) {
+ SkScalar advance = paint.measureText(kText, sizeof(kText) - 1, &bounds);
+
+ paint.setStrokeWidth(0.0f);
+ paint.setStyle(SkPaint::kStroke_Style);
+
+ // Green box is the measured text bounds.
+ paint.setColor(SK_ColorGREEN);
+ canvas->drawRect(bounds, paint);
+
+ // Red line is the measured advance from the 0,0 of the text position.
+ paint.setColor(SK_ColorRED);
+ canvas->drawLine(0.0f, 0.0f, advance, 0.0f, paint);
+ }
+
+ // Black text is the testcase, eg. the text.
+ paint.setColor(SK_ColorBLACK);
+ paint.setStrokeWidth(fStrokeWidth);
+ paint.setStyle(fStrokeStyle);
+ canvas->drawText(kText, sizeof(kText) - 1, 0.0f, 0.0f, paint);
+
+ if (drawRef) {
+ SkScalar widths[sizeof(kText) - 1];
+ paint.getTextWidths(kText, sizeof(kText) - 1, widths, NULL);
+
+ paint.setStrokeWidth(0.0f);
+ paint.setStyle(SkPaint::kStroke_Style);
+
+ // Magenta lines are the positions for the characters.
+ paint.setColor(SK_ColorMAGENTA);
+ SkScalar w = bounds.x();
+ for (size_t i = 0; i < sizeof(kText) - 1; ++i) {
+ canvas->drawLine(w, 0.0f, w, 5.0f, paint);
+ w += widths[i];
+ }
+ }
+ }
+
+private:
+ SkAutoTUnref<SkTypeface> fProp;
+ SkScalar fStrokeWidth;
+ SkPaint::Style fStrokeStyle;
+
+ typedef GM INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static GM* GlyphPosHairlineStrokeAndFillFactory(void*) {
+ return new GlyphPosGM(0.0f, SkPaint::kStrokeAndFill_Style);
+}
+static GM* GlyphPosStrokeAndFillFactory(void*) {
+ return new GlyphPosGM(1.2f, SkPaint::kStrokeAndFill_Style);
+}
+static GM* GlyphPosHairlineStrokeFactory(void*) {
+ return new GlyphPosGM(0.0f, SkPaint::kStroke_Style);
+}
+static GM* GlyphPosStrokeFactory(void*) {
+ return new GlyphPosGM(1.2f, SkPaint::kStroke_Style);
+}
+static GM* GlyphPosHairlineFillFactory(void*) {
+ return new GlyphPosGM(0.0f, SkPaint::kFill_Style);
+}
+static GM* GlyphPosFillFactory(void*) {
+ return new GlyphPosGM(1.2f, SkPaint::kFill_Style);
+}
+
+static GMRegistry reg1(GlyphPosHairlineStrokeAndFillFactory);
+static GMRegistry reg2(GlyphPosStrokeAndFillFactory);
+static GMRegistry reg3(GlyphPosHairlineStrokeFactory);
+static GMRegistry reg4(GlyphPosStrokeFactory);
+static GMRegistry reg5(GlyphPosHairlineFillFactory);
+static GMRegistry reg6(GlyphPosFillFactory);
+
+
+}