105b48e2a24ae78312c80ed94195f0b705fdb0547halcanary/*
205b48e2a24ae78312c80ed94195f0b705fdb0547halcanary * Copyright 2015 Google Inc.
305b48e2a24ae78312c80ed94195f0b705fdb0547halcanary *
405b48e2a24ae78312c80ed94195f0b705fdb0547halcanary * Use of this source code is governed by a BSD-style license that can be
505b48e2a24ae78312c80ed94195f0b705fdb0547halcanary * found in the LICENSE file.
605b48e2a24ae78312c80ed94195f0b705fdb0547halcanary */
705b48e2a24ae78312c80ed94195f0b705fdb0547halcanary
805b48e2a24ae78312c80ed94195f0b705fdb0547halcanary#include "gm.h"
933d2055e594177b27360f84e0631b26d74a55a9bMike Klein#include "sk_tool_utils.h"
1005b48e2a24ae78312c80ed94195f0b705fdb0547halcanary#include "SkImage.h"
1105b48e2a24ae78312c80ed94195f0b705fdb0547halcanary#include "SkRRect.h"
1205b48e2a24ae78312c80ed94195f0b705fdb0547halcanary
1305b48e2a24ae78312c80ed94195f0b705fdb0547halcanarystatic void rotated_checkerboard_shader(SkPaint* paint,
1405b48e2a24ae78312c80ed94195f0b705fdb0547halcanary                                        SkColor c1,
1505b48e2a24ae78312c80ed94195f0b705fdb0547halcanary                                        SkColor c2,
1605b48e2a24ae78312c80ed94195f0b705fdb0547halcanary                                        int size) {
1705b48e2a24ae78312c80ed94195f0b705fdb0547halcanary    SkBitmap bm;
1805b48e2a24ae78312c80ed94195f0b705fdb0547halcanary    bm.allocN32Pixels(2 * size, 2 * size);
1905b48e2a24ae78312c80ed94195f0b705fdb0547halcanary    bm.eraseColor(c1);
2005b48e2a24ae78312c80ed94195f0b705fdb0547halcanary    bm.eraseArea(SkIRect::MakeLTRB(0, 0, size, size), c2);
2105b48e2a24ae78312c80ed94195f0b705fdb0547halcanary    bm.eraseArea(SkIRect::MakeLTRB(size, size, 2 * size, 2 * size), c2);
2205b48e2a24ae78312c80ed94195f0b705fdb0547halcanary    SkMatrix matrix;
2305b48e2a24ae78312c80ed94195f0b705fdb0547halcanary    matrix.setScale(0.75f, 0.75f);
2405b48e2a24ae78312c80ed94195f0b705fdb0547halcanary    matrix.preRotate(30.0f);
251a9b9640843a64af8d9d90337ec3b3fea663196areed    paint->setShader(
261a9b9640843a64af8d9d90337ec3b3fea663196areed            SkShader::MakeBitmapShader(bm, SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode,
271a9b9640843a64af8d9d90337ec3b3fea663196areed                                       &matrix));
2805b48e2a24ae78312c80ed94195f0b705fdb0547halcanary}
2905b48e2a24ae78312c80ed94195f0b705fdb0547halcanary
3005b48e2a24ae78312c80ed94195f0b705fdb0547halcanarystatic void exercise_draw_pos_text(SkCanvas* canvas,
3105b48e2a24ae78312c80ed94195f0b705fdb0547halcanary                                   const char* text,
3205b48e2a24ae78312c80ed94195f0b705fdb0547halcanary                                   SkScalar x, SkScalar y,
3305b48e2a24ae78312c80ed94195f0b705fdb0547halcanary                                   const SkPaint& paint) {
3405b48e2a24ae78312c80ed94195f0b705fdb0547halcanary    size_t textLen = strlen(text);
3505b48e2a24ae78312c80ed94195f0b705fdb0547halcanary    int count = paint.countText(text, textLen);
3605b48e2a24ae78312c80ed94195f0b705fdb0547halcanary    SkAutoTArray<SkScalar> widths(count);
3705b48e2a24ae78312c80ed94195f0b705fdb0547halcanary    paint.getTextWidths(text, textLen, &widths[0]);
3805b48e2a24ae78312c80ed94195f0b705fdb0547halcanary    SkAutoTArray<SkPoint> pos(count);
3905b48e2a24ae78312c80ed94195f0b705fdb0547halcanary    for (int i = 0; i < count; ++i) {
4005b48e2a24ae78312c80ed94195f0b705fdb0547halcanary        pos[i].set(x, y);
4105b48e2a24ae78312c80ed94195f0b705fdb0547halcanary        x += widths[i];
4205b48e2a24ae78312c80ed94195f0b705fdb0547halcanary    }
4305b48e2a24ae78312c80ed94195f0b705fdb0547halcanary    canvas->drawPosText(text, textLen, &pos[0], paint);
4405b48e2a24ae78312c80ed94195f0b705fdb0547halcanary}
4505b48e2a24ae78312c80ed94195f0b705fdb0547halcanary
4605b48e2a24ae78312c80ed94195f0b705fdb0547halcanarystatic void exercise_draw_pos_text_h(SkCanvas* canvas,
4705b48e2a24ae78312c80ed94195f0b705fdb0547halcanary                                     const char* text,
4805b48e2a24ae78312c80ed94195f0b705fdb0547halcanary                                     SkScalar x, SkScalar y,
4905b48e2a24ae78312c80ed94195f0b705fdb0547halcanary                                     const SkPaint& paint) {
5005b48e2a24ae78312c80ed94195f0b705fdb0547halcanary    size_t textLen = strlen(text);
5105b48e2a24ae78312c80ed94195f0b705fdb0547halcanary    int count = paint.countText(text, textLen);
5205b48e2a24ae78312c80ed94195f0b705fdb0547halcanary    SkAutoTArray<SkScalar> widths(count);
5305b48e2a24ae78312c80ed94195f0b705fdb0547halcanary    paint.getTextWidths(text, textLen, &widths[0]);
5405b48e2a24ae78312c80ed94195f0b705fdb0547halcanary    SkAutoTArray<SkScalar> pos(count);
5505b48e2a24ae78312c80ed94195f0b705fdb0547halcanary    for (int i = 0; i < count; ++i) {
5605b48e2a24ae78312c80ed94195f0b705fdb0547halcanary        pos[i] = x;
5705b48e2a24ae78312c80ed94195f0b705fdb0547halcanary        x += widths[i];
5805b48e2a24ae78312c80ed94195f0b705fdb0547halcanary    }
5905b48e2a24ae78312c80ed94195f0b705fdb0547halcanary    canvas->drawPosTextH(text, textLen, &pos[0], y, paint);
6005b48e2a24ae78312c80ed94195f0b705fdb0547halcanary}
6105b48e2a24ae78312c80ed94195f0b705fdb0547halcanary
6205b48e2a24ae78312c80ed94195f0b705fdb0547halcanarystatic void test_text(SkCanvas* canvas, SkScalar size,
6305b48e2a24ae78312c80ed94195f0b705fdb0547halcanary                      SkColor color, SkScalar Y) {
6405b48e2a24ae78312c80ed94195f0b705fdb0547halcanary    SkPaint type;
6505b48e2a24ae78312c80ed94195f0b705fdb0547halcanary    type.setTextSize(24);
6605b48e2a24ae78312c80ed94195f0b705fdb0547halcanary    sk_tool_utils::set_portable_typeface(&type);
6705b48e2a24ae78312c80ed94195f0b705fdb0547halcanary    type.setColor(color);
6805b48e2a24ae78312c80ed94195f0b705fdb0547halcanary    const char text[] = "HELLO WORLD";
6905b48e2a24ae78312c80ed94195f0b705fdb0547halcanary    canvas->drawText(text, strlen(text), 32, size / 2 + Y, type);
7005b48e2a24ae78312c80ed94195f0b705fdb0547halcanary    SkScalar lineSpacing = type.getFontSpacing();
7105b48e2a24ae78312c80ed94195f0b705fdb0547halcanary    exercise_draw_pos_text(canvas, text, 32, size / 2 + Y + lineSpacing, type);
7205b48e2a24ae78312c80ed94195f0b705fdb0547halcanary    exercise_draw_pos_text_h(canvas, text, 32,
7305b48e2a24ae78312c80ed94195f0b705fdb0547halcanary                             size / 2 + Y + 2 * lineSpacing, type);
7405b48e2a24ae78312c80ed94195f0b705fdb0547halcanary}
7505b48e2a24ae78312c80ed94195f0b705fdb0547halcanary
7605b48e2a24ae78312c80ed94195f0b705fdb0547halcanary// If this GM works correctly, the cyan layer should be lined up with
7705b48e2a24ae78312c80ed94195f0b705fdb0547halcanary// the objects below it.
7805b48e2a24ae78312c80ed94195f0b705fdb0547halcanaryDEF_SIMPLE_GM(skbug_257, canvas, 512, 512) {
7905b48e2a24ae78312c80ed94195f0b705fdb0547halcanary    const SkScalar size = 256;
8005b48e2a24ae78312c80ed94195f0b705fdb0547halcanary    SkAutoCanvasRestore autoCanvasRestore0(canvas, true);
8105b48e2a24ae78312c80ed94195f0b705fdb0547halcanary    const SkScalar scale = 1.00168f;
8205b48e2a24ae78312c80ed94195f0b705fdb0547halcanary    canvas->scale(scale, scale);
8305b48e2a24ae78312c80ed94195f0b705fdb0547halcanary    {
8405b48e2a24ae78312c80ed94195f0b705fdb0547halcanary        SkPaint checker;
8505b48e2a24ae78312c80ed94195f0b705fdb0547halcanary        rotated_checkerboard_shader(&checker, SK_ColorWHITE, SK_ColorBLACK, 16);
8605b48e2a24ae78312c80ed94195f0b705fdb0547halcanary        checker.setAntiAlias(true);
8705b48e2a24ae78312c80ed94195f0b705fdb0547halcanary
8805b48e2a24ae78312c80ed94195f0b705fdb0547halcanary        SkAutoCanvasRestore autoCanvasRestore(canvas, true);
8905b48e2a24ae78312c80ed94195f0b705fdb0547halcanary        canvas->clear(0xFFCECFCE);
9005b48e2a24ae78312c80ed94195f0b705fdb0547halcanary        SkScalar translate = 225364.0f;
9105b48e2a24ae78312c80ed94195f0b705fdb0547halcanary        canvas->translate(0, -translate);
9205b48e2a24ae78312c80ed94195f0b705fdb0547halcanary
9305b48e2a24ae78312c80ed94195f0b705fdb0547halcanary        // Test rects
9405b48e2a24ae78312c80ed94195f0b705fdb0547halcanary        SkRect rect = SkRect::MakeLTRB(8, 8 + translate, size - 8,
9505b48e2a24ae78312c80ed94195f0b705fdb0547halcanary                                       size - 8 + translate);
9605b48e2a24ae78312c80ed94195f0b705fdb0547halcanary        canvas->drawRect(rect, checker);
9705b48e2a24ae78312c80ed94195f0b705fdb0547halcanary
9805b48e2a24ae78312c80ed94195f0b705fdb0547halcanary        // Test Paths
9905b48e2a24ae78312c80ed94195f0b705fdb0547halcanary        canvas->translate(size, 0);
10005b48e2a24ae78312c80ed94195f0b705fdb0547halcanary        SkRRect rrect;
10105b48e2a24ae78312c80ed94195f0b705fdb0547halcanary        SkVector radii[4] = {{40, 40}, {40, 40}, {40, 40}, {40, 40}};
10205b48e2a24ae78312c80ed94195f0b705fdb0547halcanary        rrect.setRectRadii(rect, radii);
10305b48e2a24ae78312c80ed94195f0b705fdb0547halcanary        canvas->drawRRect(rrect, checker);
10405b48e2a24ae78312c80ed94195f0b705fdb0547halcanary
10505b48e2a24ae78312c80ed94195f0b705fdb0547halcanary        // Test Points
10605b48e2a24ae78312c80ed94195f0b705fdb0547halcanary        canvas->translate(-size, size);
10705b48e2a24ae78312c80ed94195f0b705fdb0547halcanary        SkScalar delta = 1.0 / 64.0;
10805b48e2a24ae78312c80ed94195f0b705fdb0547halcanary        SkPoint points[8] = {{size / 2, 8 + translate},
10905b48e2a24ae78312c80ed94195f0b705fdb0547halcanary                             {size / 2, 8 + translate + delta},
11005b48e2a24ae78312c80ed94195f0b705fdb0547halcanary                             {8, size / 2 + translate},
11105b48e2a24ae78312c80ed94195f0b705fdb0547halcanary                             {8, size / 2 + translate + delta},
11205b48e2a24ae78312c80ed94195f0b705fdb0547halcanary                             {size / 2, size - 8 + translate},
11305b48e2a24ae78312c80ed94195f0b705fdb0547halcanary                             {size / 2, size - 8 + translate + delta},
11405b48e2a24ae78312c80ed94195f0b705fdb0547halcanary                             {size - 8, size / 2 + translate},
11505b48e2a24ae78312c80ed94195f0b705fdb0547halcanary                             {size - 8, size / 2 + translate + delta}};
11605b48e2a24ae78312c80ed94195f0b705fdb0547halcanary        checker.setStyle(SkPaint::kStroke_Style);
11705b48e2a24ae78312c80ed94195f0b705fdb0547halcanary        checker.setStrokeWidth(8);
11805b48e2a24ae78312c80ed94195f0b705fdb0547halcanary        checker.setStrokeCap(SkPaint::kRound_Cap);
11905b48e2a24ae78312c80ed94195f0b705fdb0547halcanary        canvas->drawPoints(SkCanvas::kLines_PointMode, 8, points, checker);
12005b48e2a24ae78312c80ed94195f0b705fdb0547halcanary
12105b48e2a24ae78312c80ed94195f0b705fdb0547halcanary        // Test Text
12205b48e2a24ae78312c80ed94195f0b705fdb0547halcanary        canvas->translate(size, 0);
12305b48e2a24ae78312c80ed94195f0b705fdb0547halcanary        test_text(canvas, size, SK_ColorBLACK, translate);
12405b48e2a24ae78312c80ed94195f0b705fdb0547halcanary    }
12505b48e2a24ae78312c80ed94195f0b705fdb0547halcanary    // reference points (without the huge translations).
12605b48e2a24ae78312c80ed94195f0b705fdb0547halcanary    SkPaint stroke;
12705b48e2a24ae78312c80ed94195f0b705fdb0547halcanary    stroke.setStyle(SkPaint::kStroke_Style);
12805b48e2a24ae78312c80ed94195f0b705fdb0547halcanary    stroke.setStrokeWidth(5);
12905b48e2a24ae78312c80ed94195f0b705fdb0547halcanary    stroke.setColor(SK_ColorCYAN);
13005b48e2a24ae78312c80ed94195f0b705fdb0547halcanary    canvas->drawCircle(size / 2, size / 2, size / 2 - 10, stroke);
13105b48e2a24ae78312c80ed94195f0b705fdb0547halcanary    canvas->drawCircle(3 * size / 2, size / 2, size / 2 - 10, stroke);
13205b48e2a24ae78312c80ed94195f0b705fdb0547halcanary    canvas->drawCircle(size / 2, 384, size / 2 - 10, stroke);
13305b48e2a24ae78312c80ed94195f0b705fdb0547halcanary    canvas->translate(size, size);
13405b48e2a24ae78312c80ed94195f0b705fdb0547halcanary    test_text(canvas, size, SK_ColorCYAN, 0.0f);
13505b48e2a24ae78312c80ed94195f0b705fdb0547halcanary}
136