| /* | |
| * Copyright 2013 Google Inc. | |
| * | |
| * Use of this source code is governed by a BSD-style license that can be | |
| * found in the LICENSE file. | |
| */ | |
| #include "gm/gm.h" | |
| #include "include/core/SkCanvas.h" | |
| #include "include/core/SkColor.h" | |
| #include "include/core/SkPaint.h" | |
| #include "include/core/SkPathBuilder.h" | |
| #include "include/core/SkRRect.h" | |
| #include "include/core/SkRect.h" | |
| #include "include/core/SkScalar.h" | |
| #include "include/core/SkSize.h" | |
| #include "include/core/SkString.h" | |
| #include "include/core/SkTypes.h" | |
| #include "src/core/SkRandom.h" | |
| #include <array> | |
| namespace skiagm { | |
| // Test out various combinations of nested rects, ovals and rrects. | |
| class NestedGM : public GM { | |
| public: | |
| NestedGM(bool doAA, bool flipped) : fDoAA(doAA), fFlipped(flipped) { | |
| this->setBGColor(0xFFDDDDDD); | |
| } | |
| protected: | |
| SkString getName() const override { | |
| SkString name("nested"); | |
| if (fFlipped) { | |
| name.append("_flipY"); | |
| } | |
| if (fDoAA) { | |
| name.append("_aa"); | |
| } else { | |
| name.append("_bw"); | |
| } | |
| return name; | |
| } | |
| SkISize getISize() override { return SkISize::Make(kImageWidth, kImageHeight); } | |
| enum Shapes { | |
| kRect_Shape = 0, | |
| kRRect_Shape, | |
| kOval_Shape, | |
| kShapeCount | |
| }; | |
| static void AddShape(SkPathBuilder* b, const SkRect& rect, Shapes shape, SkPathDirection dir) { | |
| switch (shape) { | |
| case kRect_Shape: | |
| b->addRect(rect, dir); | |
| break; | |
| case kRRect_Shape: { | |
| SkRRect rr; | |
| rr.setRectXY(rect, 5, 5); | |
| b->addRRect(rr, dir); | |
| break; | |
| } | |
| case kOval_Shape: | |
| b->addOval(rect, dir); | |
| break; | |
| default: | |
| break; | |
| } | |
| } | |
| void onDraw(SkCanvas* canvas) override { | |
| SkPaint shapePaint; | |
| shapePaint.setColor(SK_ColorBLACK); | |
| shapePaint.setAntiAlias(fDoAA); | |
| SkRect outerRect = SkRect::MakeWH(40, 40); | |
| static constexpr auto innerRects = std::to_array<SkRect>({ | |
| SkRect{ 10, 10, 30, 30}, // small | |
| SkRect{ .5f, 18, 4.5f, 22} // smaller and offset to left | |
| }); | |
| // draw a background pattern to make transparency errors more apparent | |
| SkRandom rand; | |
| for (int y = 0; y < kImageHeight; y += 10) { | |
| for (int x = 0; x < kImageWidth; x += 10) { | |
| SkRect r = SkRect::MakeXYWH(SkIntToScalar(x), | |
| SkIntToScalar(y), | |
| 10, 10); | |
| SkPaint p; | |
| p.setColor(rand.nextU() | 0xFF000000); | |
| canvas->drawRect(r, p); | |
| } | |
| } | |
| SkScalar xOff = 2, yOff = 2; | |
| for (int outerShape = 0; outerShape < kShapeCount; ++outerShape) { | |
| for (int innerShape = 0; innerShape < kShapeCount; ++innerShape) { | |
| for (size_t innerRect = 0; innerRect < std::size(innerRects); ++innerRect) { | |
| SkPathBuilder builder; | |
| AddShape(&builder, outerRect, (Shapes) outerShape, SkPathDirection::kCW); | |
| AddShape(&builder, innerRects[innerRect], (Shapes) innerShape, | |
| SkPathDirection::kCCW); | |
| canvas->save(); | |
| if (fFlipped) { | |
| canvas->scale(1.0f, -1.0f); | |
| canvas->translate(xOff, -yOff - 40.0f); | |
| } else { | |
| canvas->translate(xOff, yOff); | |
| } | |
| canvas->drawPath(builder.detach(), shapePaint); | |
| canvas->restore(); | |
| xOff += 45; | |
| } | |
| } | |
| xOff = 2; | |
| yOff += 45; | |
| } | |
| } | |
| private: | |
| inline static constexpr int kImageWidth = 269; | |
| inline static constexpr int kImageHeight = 134; | |
| bool fDoAA; | |
| bool fFlipped; | |
| using INHERITED = GM; | |
| }; | |
| /////////////////////////////////////////////////////////////////////////////// | |
| DEF_GM( return new NestedGM(/* doAA = */ true, /* flipped = */ false); ) | |
| DEF_GM( return new NestedGM(/* doAA = */ false, /* flipped = */ false); ) | |
| DEF_GM( return new NestedGM(/* doAA = */ true, /* flipped = */ true); ) | |
| DEF_GM( return new NestedGM(/* doAA = */ false, /* flipped = */ true); ) | |
| DEF_SIMPLE_GM(nested_hairline_square, canvas, 64, 64) { | |
| // See crbug.com/1234194 - This should draw 1 row of 3 stroked squares, with a second 0.5px | |
| // shifted row of squares below it. | |
| auto drawEllipses = [&]() { | |
| canvas->save(); | |
| // Originally the SVG string "M5,14H0V9h5V14Z M1,13h3v-3H1V13Z" but that just specifies a | |
| // 5px wide square outside a 3px wide square. | |
| SkPath square = SkPathBuilder() | |
| .addRect(SkRect::MakeLTRB(0.f, 9.f, 5.f, 14.f)) | |
| .addRect(SkRect::MakeLTRB(1.f, 10.f, 4.f, 13.f), SkPathDirection::kCCW) | |
| .detach(); | |
| // From the bug, SVG viewbox was (0, 0, 24, 24), so the above coordinates are relative to | |
| // that, but the svg was then the child of a div that was 16x16, so it's scaled down. This | |
| // converts the 1px wide nested rects into subpixel nested rects. | |
| canvas->scale(16.f / 24.f, 16.f / 24.f); | |
| SkPaint paint; | |
| paint.setColor(SkColorSetARGB(255, 70, 70, 70)); | |
| paint.setAntiAlias(true); | |
| // The original SVG drew 3 separate paths, but these were just translations of the original | |
| // path baked into a path string. | |
| canvas->drawPath(square, paint); | |
| canvas->translate(10.f, 0.f); | |
| canvas->drawPath(square, paint); | |
| canvas->translate(10.f, 0.f); | |
| canvas->drawPath(square, paint); | |
| canvas->restore(); | |
| }; | |
| drawEllipses(); | |
| canvas->translate(0.5f, 16.f); | |
| drawEllipses(); | |
| } | |
| } // namespace skiagm |