309 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			309 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			C++
		
	
	
	
| /*
 | |
|  * 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/gm.h"
 | |
| #include "include/core/SkBitmap.h"
 | |
| #include "include/core/SkCanvas.h"
 | |
| #include "include/core/SkClipOp.h"
 | |
| #include "include/core/SkColor.h"
 | |
| #include "include/core/SkFont.h"
 | |
| #include "include/core/SkFontTypes.h"
 | |
| #include "include/core/SkMatrix.h"
 | |
| #include "include/core/SkPaint.h"
 | |
| #include "include/core/SkPathBuilder.h"
 | |
| #include "include/core/SkPoint.h"
 | |
| #include "include/core/SkRect.h"
 | |
| #include "include/core/SkScalar.h"
 | |
| #include "include/core/SkShader.h"
 | |
| #include "include/core/SkSize.h"
 | |
| #include "include/core/SkString.h"
 | |
| #include "include/core/SkTileMode.h"
 | |
| #include "include/core/SkTypeface.h"
 | |
| #include "include/core/SkTypes.h"
 | |
| #include "include/effects/SkGradientShader.h"
 | |
| #include "tools/ToolUtils.h"
 | |
| 
 | |
| static sk_sp<SkImage> make_img(int w, int h) {
 | |
|     auto surf = SkSurface::MakeRaster(SkImageInfo::MakeN32(w, h, kOpaque_SkAlphaType));
 | |
|     auto canvas = surf->getCanvas();
 | |
| 
 | |
|     SkScalar wScalar = SkIntToScalar(w);
 | |
|     SkScalar hScalar = SkIntToScalar(h);
 | |
| 
 | |
|     SkPoint     pt = { wScalar / 2, hScalar / 2 };
 | |
| 
 | |
|     SkScalar    radius = 3 * std::max(wScalar, hScalar);
 | |
| 
 | |
|     SkColor colors[] = {SK_ColorDKGRAY,
 | |
|                         ToolUtils::color_to_565(0xFF222255),
 | |
|                         ToolUtils::color_to_565(0xFF331133),
 | |
|                         ToolUtils::color_to_565(0xFF884422),
 | |
|                         ToolUtils::color_to_565(0xFF000022),
 | |
|                         SK_ColorWHITE,
 | |
|                         ToolUtils::color_to_565(0xFFAABBCC)};
 | |
| 
 | |
|     SkScalar    pos[] = {0,
 | |
|                          SK_Scalar1 / 6,
 | |
|                          2 * SK_Scalar1 / 6,
 | |
|                          3 * SK_Scalar1 / 6,
 | |
|                          4 * SK_Scalar1 / 6,
 | |
|                          5 * SK_Scalar1 / 6,
 | |
|                          SK_Scalar1};
 | |
| 
 | |
|     SkPaint paint;
 | |
|     SkRect rect = SkRect::MakeWH(wScalar, hScalar);
 | |
|     SkMatrix mat = SkMatrix::I();
 | |
|     for (int i = 0; i < 4; ++i) {
 | |
|         paint.setShader(SkGradientShader::MakeRadial(
 | |
|                         pt, radius,
 | |
|                         colors, pos,
 | |
|                         SK_ARRAY_COUNT(colors),
 | |
|                         SkTileMode::kRepeat,
 | |
|                         0, &mat));
 | |
|         canvas->drawRect(rect, paint);
 | |
|         rect.inset(wScalar / 8, hScalar / 8);
 | |
|         mat.preTranslate(6 * wScalar, 6 * hScalar);
 | |
|         mat.postScale(SK_Scalar1 / 3, SK_Scalar1 / 3);
 | |
|     }
 | |
| 
 | |
|     SkFont font(ToolUtils::create_portable_typeface(), wScalar / 2.2f);
 | |
| 
 | |
|     paint.setShader(nullptr);
 | |
|     paint.setColor(SK_ColorLTGRAY);
 | |
|     constexpr char kTxt[] = "Skia";
 | |
|     SkPoint texPos = { wScalar / 17, hScalar / 2 + font.getSize() / 2.5f };
 | |
|     canvas->drawSimpleText(kTxt, SK_ARRAY_COUNT(kTxt)-1, SkTextEncoding::kUTF8,
 | |
|                            texPos.fX, texPos.fY, font, paint);
 | |
|     paint.setColor(SK_ColorBLACK);
 | |
|     paint.setStyle(SkPaint::kStroke_Style);
 | |
|     paint.setStrokeWidth(SK_Scalar1);
 | |
|     canvas->drawSimpleText(kTxt, SK_ARRAY_COUNT(kTxt)-1, SkTextEncoding::kUTF8,
 | |
|                            texPos.fX, texPos.fY, font, paint);
 | |
|     return surf->makeImageSnapshot();
 | |
| }
 | |
| 
 | |
| namespace skiagm {
 | |
| /**
 | |
|  * This GM tests convex polygon clips.
 | |
|  */
 | |
| class ConvexPolyClip : public GM {
 | |
| public:
 | |
|     ConvexPolyClip() {
 | |
|         this->setBGColor(0xFFFFFFFF);
 | |
|     }
 | |
| 
 | |
| protected:
 | |
|     SkString onShortName() override {
 | |
|         return SkString("convex_poly_clip");
 | |
|     }
 | |
| 
 | |
|     SkISize onISize() override {
 | |
|         // When benchmarking the saveLayer set of draws is skipped.
 | |
|         int w = 435;
 | |
|         if (kBench_Mode != this->getMode()) {
 | |
|             w *= 2;
 | |
|         }
 | |
|         return SkISize::Make(w, 540);
 | |
|     }
 | |
| 
 | |
|     void onOnceBeforeDraw() override {
 | |
|         // On < c++17, emplace_back() returns a void :(
 | |
|         auto emplace_back = [](std::vector<Clip>& clips) -> Clip& {
 | |
|             clips.emplace_back();
 | |
|             return clips.back();
 | |
|         };
 | |
| 
 | |
|         emplace_back(fClips).setPath(SkPath::Polygon({
 | |
|             {  5.f,   5.f},
 | |
|             {100.f,  20.f},
 | |
|             { 15.f, 100.f},
 | |
|         }, false));
 | |
| 
 | |
|         SkPathBuilder hexagon;
 | |
|         constexpr SkScalar kRadius = 45.f;
 | |
|         const SkPoint center = { kRadius, kRadius };
 | |
|         for (int i = 0; i < 6; ++i) {
 | |
|             SkScalar angle = 2 * SK_ScalarPI * i / 6;
 | |
|             SkPoint point = { SkScalarCos(angle), SkScalarSin(angle) };
 | |
|             point.scale(kRadius);
 | |
|             point = center + point;
 | |
|             if (0 == i) {
 | |
|                 hexagon.moveTo(point);
 | |
|             } else {
 | |
|                 hexagon.lineTo(point);
 | |
|             }
 | |
|         }
 | |
|         emplace_back(fClips).setPath(hexagon.snapshot());
 | |
| 
 | |
|         SkMatrix scaleM;
 | |
|         scaleM.setScale(1.1f, 0.4f, kRadius, kRadius);
 | |
|         emplace_back(fClips).setPath(hexagon.detach().makeTransform(scaleM));
 | |
| 
 | |
|         emplace_back(fClips).setRect(SkRect::MakeXYWH(8.3f, 11.6f, 78.2f, 72.6f));
 | |
| 
 | |
|         SkRect rect = SkRect::MakeLTRB(10.f, 12.f, 80.f, 86.f);
 | |
|         SkMatrix rotM;
 | |
|         rotM.setRotate(23.f, rect.centerX(), rect.centerY());
 | |
|         emplace_back(fClips).setPath(SkPath::Rect(rect).makeTransform(rotM));
 | |
| 
 | |
|         fImg = make_img(100, 100);
 | |
|     }
 | |
| 
 | |
|     void onDraw(SkCanvas* canvas) override {
 | |
|         SkScalar y = 0;
 | |
|         constexpr SkScalar kMargin = 10.f;
 | |
| 
 | |
|         SkPaint bgPaint;
 | |
|         bgPaint.setAlpha(0x15);
 | |
|         SkISize size = canvas->getBaseLayerSize();
 | |
|         canvas->drawImageRect(fImg, SkRect::MakeIWH(size.fWidth, size.fHeight),
 | |
|                               SkSamplingOptions(), &bgPaint);
 | |
| 
 | |
|         constexpr char kTxt[] = "Clip Me!";
 | |
|         SkFont         font(ToolUtils::create_portable_typeface(), 23);
 | |
|         SkScalar textW = font.measureText(kTxt, SK_ARRAY_COUNT(kTxt)-1, SkTextEncoding::kUTF8);
 | |
|         SkPaint txtPaint;
 | |
|         txtPaint.setColor(SK_ColorDKGRAY);
 | |
| 
 | |
|         SkScalar startX = 0;
 | |
|         int testLayers = kBench_Mode != this->getMode();
 | |
|         for (int doLayer = 0; doLayer <= testLayers; ++doLayer) {
 | |
|             for (const Clip& clip : fClips) {
 | |
|                 SkScalar x = startX;
 | |
|                 for (int aa = 0; aa < 2; ++aa) {
 | |
|                     if (doLayer) {
 | |
|                         SkRect bounds;
 | |
|                         clip.getBounds(&bounds);
 | |
|                         bounds.outset(2, 2);
 | |
|                         bounds.offset(x, y);
 | |
|                         canvas->saveLayer(&bounds, nullptr);
 | |
|                     } else {
 | |
|                         canvas->save();
 | |
|                     }
 | |
|                     canvas->translate(x, y);
 | |
|                     clip.setOnCanvas(canvas, SkClipOp::kIntersect, SkToBool(aa));
 | |
|                     canvas->drawImage(fImg, 0, 0);
 | |
|                     canvas->restore();
 | |
|                     x += fImg->width() + kMargin;
 | |
|                 }
 | |
|                 for (int aa = 0; aa < 2; ++aa) {
 | |
| 
 | |
|                     SkPaint clipOutlinePaint;
 | |
|                     clipOutlinePaint.setAntiAlias(true);
 | |
|                     clipOutlinePaint.setColor(0x50505050);
 | |
|                     clipOutlinePaint.setStyle(SkPaint::kStroke_Style);
 | |
|                     clipOutlinePaint.setStrokeWidth(0);
 | |
| 
 | |
|                     if (doLayer) {
 | |
|                         SkRect bounds;
 | |
|                         clip.getBounds(&bounds);
 | |
|                         bounds.outset(2, 2);
 | |
|                         bounds.offset(x, y);
 | |
|                         canvas->saveLayer(&bounds, nullptr);
 | |
|                     } else {
 | |
|                         canvas->save();
 | |
|                     }
 | |
|                     canvas->translate(x, y);
 | |
|                     SkPath closedClipPath = clip.asClosedPath();
 | |
|                     canvas->drawPath(closedClipPath, clipOutlinePaint);
 | |
|                     clip.setOnCanvas(canvas, SkClipOp::kIntersect, SkToBool(aa));
 | |
|                     canvas->scale(1.f, 1.8f);
 | |
|                     canvas->drawSimpleText(kTxt, SK_ARRAY_COUNT(kTxt)-1, SkTextEncoding::kUTF8,
 | |
|                                      0, 1.5f * font.getSize(), font, txtPaint);
 | |
|                     canvas->restore();
 | |
|                     x += textW + 2 * kMargin;
 | |
|                 }
 | |
|                 y += fImg->height() + kMargin;
 | |
|             }
 | |
|             y = 0;
 | |
|             startX += 2 * fImg->width() + SkScalarCeilToInt(2 * textW) + 6 * kMargin;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     bool runAsBench() const override { return true; }
 | |
| 
 | |
| private:
 | |
|     class Clip {
 | |
|     public:
 | |
|         enum ClipType {
 | |
|             kNone_ClipType,
 | |
|             kPath_ClipType,
 | |
|             kRect_ClipType
 | |
|         };
 | |
| 
 | |
|         Clip () : fClipType(kNone_ClipType) {}
 | |
| 
 | |
|         void setOnCanvas(SkCanvas* canvas, SkClipOp op, bool aa) const {
 | |
|             switch (fClipType) {
 | |
|                 case kPath_ClipType:
 | |
|                     canvas->clipPath(fPathBuilder.snapshot(), op, aa);
 | |
|                     break;
 | |
|                 case kRect_ClipType:
 | |
|                     canvas->clipRect(fRect, op, aa);
 | |
|                     break;
 | |
|                 case kNone_ClipType:
 | |
|                     SkDEBUGFAIL("Uninitialized Clip.");
 | |
|                     break;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         SkPath asClosedPath() const {
 | |
|             switch (fClipType) {
 | |
|                 case kPath_ClipType:
 | |
|                     return SkPathBuilder(fPathBuilder).close().detach();
 | |
|                     break;
 | |
|                 case kRect_ClipType:
 | |
|                     return SkPath::Rect(fRect);
 | |
|                 case kNone_ClipType:
 | |
|                     SkDEBUGFAIL("Uninitialized Clip.");
 | |
|                     break;
 | |
|             }
 | |
|             return SkPath();
 | |
|         }
 | |
| 
 | |
|         void setPath(const SkPath& path) {
 | |
|             fClipType = kPath_ClipType;
 | |
|             fPathBuilder = path;
 | |
|         }
 | |
| 
 | |
|         void setRect(const SkRect& rect) {
 | |
|             fClipType = kRect_ClipType;
 | |
|             fRect = rect;
 | |
|             fPathBuilder.reset();
 | |
|         }
 | |
| 
 | |
|         ClipType getType() const { return fClipType; }
 | |
| 
 | |
|         void getBounds(SkRect* bounds) const {
 | |
|             switch (fClipType) {
 | |
|                 case kPath_ClipType:
 | |
|                     *bounds = fPathBuilder.computeBounds();
 | |
|                     break;
 | |
|                 case kRect_ClipType:
 | |
|                     *bounds = fRect;
 | |
|                     break;
 | |
|                 case kNone_ClipType:
 | |
|                     SkDEBUGFAIL("Uninitialized Clip.");
 | |
|                     break;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|     private:
 | |
|         ClipType fClipType;
 | |
|         SkPathBuilder fPathBuilder;
 | |
|         SkRect fRect;
 | |
|     };
 | |
| 
 | |
|     std::vector<Clip> fClips;
 | |
|     sk_sp<SkImage>    fImg;;
 | |
| 
 | |
|     using INHERITED = GM;
 | |
| };
 | |
| 
 | |
| DEF_GM(return new ConvexPolyClip;)
 | |
| }  // namespace skiagm
 |