/* * Copyright 2015 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 "sk_tool_utils.h" #include "SkImage.h" #include "SkRRect.h" static void rotated_checkerboard_shader(SkPaint* paint, SkColor c1, SkColor c2, int size) { SkBitmap bm; bm.allocN32Pixels(2 * size, 2 * size); bm.eraseColor(c1); bm.eraseArea(SkIRect::MakeLTRB(0, 0, size, size), c2); bm.eraseArea(SkIRect::MakeLTRB(size, size, 2 * size, 2 * size), c2); SkMatrix matrix; matrix.setScale(0.75f, 0.75f); matrix.preRotate(30.0f); paint->setShader( SkShader::MakeBitmapShader(bm, SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode, &matrix)); } static void exercise_draw_pos_text(SkCanvas* canvas, const char* text, SkScalar x, SkScalar y, const SkPaint& paint) { size_t textLen = strlen(text); int count = paint.countText(text, textLen); SkAutoTArray<SkScalar> widths(count); paint.getTextWidths(text, textLen, &widths[0]); SkAutoTArray<SkPoint> pos(count); for (int i = 0; i < count; ++i) { pos[i].set(x, y); x += widths[i]; } canvas->drawPosText(text, textLen, &pos[0], paint); } static void exercise_draw_pos_text_h(SkCanvas* canvas, const char* text, SkScalar x, SkScalar y, const SkPaint& paint) { size_t textLen = strlen(text); int count = paint.countText(text, textLen); SkAutoTArray<SkScalar> widths(count); paint.getTextWidths(text, textLen, &widths[0]); SkAutoTArray<SkScalar> pos(count); for (int i = 0; i < count; ++i) { pos[i] = x; x += widths[i]; } canvas->drawPosTextH(text, textLen, &pos[0], y, paint); } static void test_text(SkCanvas* canvas, SkScalar size, SkColor color, SkScalar Y) { SkPaint type; type.setTextSize(24); sk_tool_utils::set_portable_typeface(&type); type.setColor(color); const char text[] = "HELLO WORLD"; canvas->drawString(text, 32, size / 2 + Y, type); SkScalar lineSpacing = type.getFontSpacing(); exercise_draw_pos_text(canvas, text, 32, size / 2 + Y + lineSpacing, type); exercise_draw_pos_text_h(canvas, text, 32, size / 2 + Y + 2 * lineSpacing, type); } // If this GM works correctly, the cyan layer should be lined up with // the objects below it. DEF_SIMPLE_GM(skbug_257, canvas, 512, 512) { const SkScalar size = 256; SkAutoCanvasRestore autoCanvasRestore0(canvas, true); const SkScalar scale = 1.00168f; canvas->scale(scale, scale); { SkPaint checker; rotated_checkerboard_shader(&checker, SK_ColorWHITE, SK_ColorBLACK, 16); checker.setAntiAlias(true); SkAutoCanvasRestore autoCanvasRestore(canvas, true); canvas->clear(0xFFCECFCE); SkScalar translate = 225364.0f; canvas->translate(0, -translate); // Test rects SkRect rect = SkRect::MakeLTRB(8, 8 + translate, size - 8, size - 8 + translate); canvas->drawRect(rect, checker); // Test Paths canvas->translate(size, 0); SkRRect rrect; SkVector radii[4] = {{40, 40}, {40, 40}, {40, 40}, {40, 40}}; rrect.setRectRadii(rect, radii); canvas->drawRRect(rrect, checker); // Test Points canvas->translate(-size, size); SkScalar delta = 1.0 / 64.0; SkPoint points[8] = {{size / 2, 8 + translate}, {size / 2, 8 + translate + delta}, {8, size / 2 + translate}, {8, size / 2 + translate + delta}, {size / 2, size - 8 + translate}, {size / 2, size - 8 + translate + delta}, {size - 8, size / 2 + translate}, {size - 8, size / 2 + translate + delta}}; checker.setStyle(SkPaint::kStroke_Style); checker.setStrokeWidth(8); checker.setStrokeCap(SkPaint::kRound_Cap); canvas->drawPoints(SkCanvas::kLines_PointMode, 8, points, checker); // Test Text canvas->translate(size, 0); test_text(canvas, size, SK_ColorBLACK, translate); } // reference points (without the huge translations). SkPaint stroke; stroke.setStyle(SkPaint::kStroke_Style); stroke.setStrokeWidth(5); stroke.setColor(SK_ColorCYAN); canvas->drawCircle(size / 2, size / 2, size / 2 - 10, stroke); canvas->drawCircle(3 * size / 2, size / 2, size / 2 - 10, stroke); canvas->drawCircle(size / 2, 384, size / 2 - 10, stroke); canvas->translate(size, size); test_text(canvas, size, SK_ColorCYAN, 0.0f); }