4#include "IGraphicsSkia.h"
7#pragma warning( disable : 4244 )
8#include "include/core/SkMaskFilter.h"
9#include "include/core/SkBlurTypes.h"
10#include "include/core/SkFont.h"
11#include "include/core/SkFontMetrics.h"
12#include "include/core/SkTypeface.h"
13#include "include/core/SkVertices.h"
14#include "include/core/SkSwizzle.h"
15#include "include/core/SkBitmap.h"
16#include "include/core/SkFontMgr.h"
17#include "include/core/SkPathEffect.h"
18#include "include/effects/SkDashPathEffect.h"
19#include "include/effects/SkGradientShader.h"
21#if !defined IGRAPHICS_NO_SKIA_SKPARAGRAPH
22#include "modules/skparagraph/include/FontCollection.h"
23#include "modules/skparagraph/include/Paragraph.h"
24#include "modules/skparagraph/include/ParagraphBuilder.h"
25#include "modules/skparagraph/include/ParagraphStyle.h"
26#include "modules/skparagraph/include/TextStyle.h"
27#include "modules/skshaper/include/SkShaper.h"
28#include "modules/skunicode/include/SkUnicode_icu.h"
31#include "include/gpu/ganesh/SkSurfaceGanesh.h"
32#include "include/gpu/GrBackendSurface.h"
34#if defined OS_MAC || defined OS_IOS
35 #include "include/utils/mac/SkCGUtils.h"
36 #if defined IGRAPHICS_GL2
37 #error SKIA doesn't work correctly with IGRAPHICS_GL2
38 #elif defined IGRAPHICS_GL3
39 #include <OpenGL/gl3.h>
40 #elif defined IGRAPHICS_METAL
42 #import <Metal/Metal.h>
43 #import <QuartzCore/CAMetalLayer.h>
44 #include "include/gpu/ganesh/mtl/GrMtlBackendContext.h"
45 #include "include/gpu/ganesh/mtl/GrMtlDirectContext.h"
46 #include "include/gpu/ganesh/mtl/GrMtlBackendSurface.h"
47 #elif !defined IGRAPHICS_CPU
48 #error Define either IGRAPHICS_GL2, IGRAPHICS_GL3, IGRAPHICS_METAL, or IGRAPHICS_CPU for IGRAPHICS_SKIA with OS_MAC
51 #include "include/ports/SkFontMgr_mac_ct.h"
54 #include "include/ports/SkTypeface_win.h"
56 #pragma comment(lib, "skia.lib")
58 #ifndef IGRAPHICS_NO_SKIA_SKPARAGRAPH
59 #pragma comment(lib, "skparagraph.lib")
60 #pragma comment(lib, "skshaper.lib")
61 #pragma comment(lib, "skunicode_core.lib")
62 #pragma comment(lib, "skunicode_icu.lib")
68#if defined IGRAPHICS_GL
69 #include "include/gpu/gl/GrGLInterface.h"
70 #include "include/gpu/ganesh/gl/GrGLDirectContext.h"
71 #include "include/gpu/ganesh/gl/GrGLBackendSurface.h"
74 #include "include/gpu/ganesh/gl/mac/GrGLMakeMacInterface.h"
76 #include "include/gpu/ganesh/gl/win/GrGLMakeWinInterface.h"
77 #pragma comment(lib, "opengl32.lib")
83using namespace igraphics;
85extern std::map<std::string, MTLTexturePtr> gTextureMap;
87#pragma mark - Private Classes and Structs
92 Bitmap(sk_sp<SkSurface> surface,
int width,
int height,
float scale,
float drawScale);
93 Bitmap(
const char* path,
double sourceScale);
94 Bitmap(
const void* pData,
int size,
double sourceScale);
95 Bitmap(sk_sp<SkImage>,
double sourceScale);
98 SkiaDrawable mDrawable;
101IGraphicsSkia::Bitmap::Bitmap(sk_sp<SkSurface> surface,
int width,
int height,
float scale,
float drawScale)
103 mDrawable.mSurface = surface;
104 mDrawable.mIsSurface =
true;
106 SetBitmap(&mDrawable, width, height, scale, drawScale);
109IGraphicsSkia::Bitmap::Bitmap(
const char* path,
double sourceScale)
111 sk_sp<SkData> data = SkData::MakeFromFileName(path);
113 assert(data &&
"Unable to load file at path");
115 auto image = SkImages::DeferredFromEncodedData(data);
118 image = image->makeRasterImage();
121 mDrawable.mImage = image;
123 mDrawable.mIsSurface =
false;
124 SetBitmap(&mDrawable, mDrawable.mImage->width(), mDrawable.mImage->height(), sourceScale, 1.f);
127IGraphicsSkia::Bitmap::Bitmap(
const void* pData,
int size,
double sourceScale)
129 auto data = SkData::MakeWithoutCopy(pData, size);
130 auto image = SkImages::DeferredFromEncodedData(data);
133 image = image->makeRasterImage();
136 mDrawable.mImage = image;
138 mDrawable.mIsSurface =
false;
139 SetBitmap(&mDrawable, mDrawable.mImage->width(), mDrawable.mImage->height(), sourceScale, 1.f);
142IGraphicsSkia::Bitmap::Bitmap(sk_sp<SkImage> image,
double sourceScale)
145 mDrawable.mImage = image->makeRasterImage();
147 mDrawable.mImage = image;
150 SetBitmap(&mDrawable, mDrawable.mImage->width(), mDrawable.mImage->height(), sourceScale, 1.f);
153struct IGraphicsSkia::Font
155 Font(IFontDataPtr&& data, sk_sp<SkTypeface> typeFace)
156 : mData(std::move(data)), mTypeface(typeFace) {}
159 sk_sp<SkTypeface> mTypeface;
163StaticStorage<IGraphicsSkia::Font> IGraphicsSkia::sFontCache;
165#pragma mark - Utility conversions
168BEGIN_IGRAPHICS_NAMESPACE
170SkColor SkiaColor(
const IColor& color,
const IBlend* pBlend)
173 return SkColorSetARGB(
Clip(
static_cast<int>(pBlend->mWeight * color.A), 0, 255), color.R, color.G, color.B);
175 return SkColorSetARGB(color.A, color.R, color.G, color.B);
178SkRect SkiaRect(
const IRECT& r)
180 return SkRect::MakeLTRB(r.L, r.T, r.R, r.B);
183SkBlendMode SkiaBlendMode(
const IBlend* pBlend)
186 return SkBlendMode::kSrcOver;
188 switch (pBlend->mMethod)
190 case EBlend::SrcOver:
return SkBlendMode::kSrcOver;
191 case EBlend::SrcIn:
return SkBlendMode::kSrcIn;
192 case EBlend::SrcOut:
return SkBlendMode::kSrcOut;
193 case EBlend::SrcAtop:
return SkBlendMode::kSrcATop;
194 case EBlend::DstOver:
return SkBlendMode::kDstOver;
195 case EBlend::DstIn:
return SkBlendMode::kDstIn;
196 case EBlend::DstOut:
return SkBlendMode::kDstOut;
197 case EBlend::DstAtop:
return SkBlendMode::kDstATop;
198 case EBlend::Add:
return SkBlendMode::kPlus;
199 case EBlend::XOR:
return SkBlendMode::kXor;
202 return SkBlendMode::kClear;
205SkTileMode SkiaTileMode(
const IPattern& pattern)
207 switch (pattern.mExtend)
209 case EPatternExtend::None:
return SkTileMode::kDecal;
210 case EPatternExtend::Reflect:
return SkTileMode::kMirror;
211 case EPatternExtend::Repeat:
return SkTileMode::kRepeat;
212 case EPatternExtend::Pad:
return SkTileMode::kClamp;
215 return SkTileMode::kClamp;
221 paint.setAntiAlias(
true);
222 paint.setBlendMode(SkiaBlendMode(pBlend));
223 int numStops = pattern.
NStops();
225 if (pattern.mType == EPatternType::Solid || numStops < 2)
227 paint.setColor(SkiaColor(pattern.
GetStop(0).mColor, pBlend));
236 IMatrix m = pattern.mTransform;
243 SkPoint::Make(x1, y1),
244 SkPoint::Make(x2, y2)
248 SkScalar positions[8];
250 assert(numStops <= 8);
252 for(
int i = 0; i < numStops; i++)
255 colors[i] = SkiaColor(stop.mColor, pBlend);
256 positions[i] = stop.mOffset;
259 switch (pattern.mType)
261 case EPatternType::Linear:
262 paint.setShader(SkGradientShader::MakeLinear(points, colors, positions, numStops, SkiaTileMode(pattern), 0,
nullptr));
265 case EPatternType::Radial:
267 float xd = points[0].x() - points[1].x();
268 float yd = points[0].y() - points[1].y();
269 float radius = std::sqrt(xd * xd + yd * yd);
270 paint.setShader(SkGradientShader::MakeRadial(points[0], radius, colors, positions, numStops, SkiaTileMode(pattern), 0,
nullptr));
274 case EPatternType::Sweep:
276 SkMatrix matrix = SkMatrix::MakeAll(m.mXX, m.mYX, 0, m.mXY, m.mYY, 0, 0, 0, 1);
278 paint.setShader(SkGradientShader::MakeSweep(x1, y1, colors,
nullptr, numStops, SkTileMode::kDecal,
279 0, 360 * positions[numStops - 1], 0, &matrix));
292END_IGRAPHICS_NAMESPACE
297static sk_sp<SkFontMgr> SFontMgrFactory()
299#if defined OS_MAC || defined OS_IOS
300 return SkFontMgr_New_CoreText(
nullptr);
302 return SkFontMgr_New_DirectWrite();
304 #error "Not supported"
308bool gFontMgrFactoryCreated =
false;
310sk_sp<SkFontMgr> SkFontMgrRefDefault()
312 static std::once_flag flag;
313 static sk_sp<SkFontMgr> mgr;
314 std::call_once(flag, [] {
315 mgr = SFontMgrFactory();
316 gFontMgrFactoryCreated =
true;
321#if !defined IGRAPHICS_NO_SKIA_SKPARAGRAPH
323bool gSkUnicodeCreated =
false;
325sk_sp<SkUnicode> GetUnicode()
327 static std::once_flag flag;
328 static sk_sp<SkUnicode> unicode;
329 std::call_once(flag, [] {
330 unicode = SkUnicodes::ICU::Make();
331 gSkUnicodeCreated =
true;
336 DBGMSG(
"Could not load unicode data\n");
344IGraphicsSkia::IGraphicsSkia(
IGEditorDelegate& dlg,
int w,
int h,
int fps,
float scale)
347 mMainPath.setIsVolatile(
true);
349#if defined IGRAPHICS_CPU
350 DBGMSG(
"IGraphics Skia CPU @ %i FPS\n", fps);
351#elif defined IGRAPHICS_METAL
352 DBGMSG(
"IGraphics Skia METAL @ %i FPS\n", fps);
353#elif defined IGRAPHICS_GL
354 DBGMSG(
"IGraphics Skia GL @ %i FPS\n", fps);
356 StaticStorage<Font>::Accessor storage(sFontCache);
359#if !defined IGRAPHICS_NO_SKIA_SKPARAGRAPH
360 mFontCollection = sk_make_sp<skia::textlayout::FontCollection>();
361 mFontCollection->enableFontFallback();
362 mFontCollection->setDefaultFontManager(SkFontMgrRefDefault());
366IGraphicsSkia::~IGraphicsSkia()
368 StaticStorage<Font>::Accessor storage(sFontCache);
376 return (strstr(extLower,
"png") !=
nullptr) || (strstr(extLower,
"jpg") !=
nullptr) || (strstr(extLower,
"jpeg") !=
nullptr);
399 if (location == EResourceLocation::kWinBinary)
403 return new Bitmap(pData, size, scale);
407 return new Bitmap(fileNameOrResID, scale);
412 return new Bitmap(pData, dataSize, scale);
417#if defined IGRAPHICS_GL
419 auto glInterface = GrGLInterfaces::MakeMac();
421 auto glInterface = GrGLInterfaces::MakeWin();
423 mGrContext = GrDirectContexts::MakeGL(glInterface);
424#elif defined IGRAPHICS_METAL
425 CAMetalLayer* pMTLLayer = (CAMetalLayer*) pContext;
426 id<MTLDevice> device = pMTLLayer.device;
427 id<MTLCommandQueue> commandQueue = [device newCommandQueue];
428 GrMtlBackendContext backendContext = {};
429 backendContext.fDevice.retain((__bridge GrMTLHandle) device);
430 backendContext.fQueue.retain((__bridge GrMTLHandle) commandQueue);
431 mGrContext = GrDirectContexts::MakeMetal(backendContext);
432 mMTLDevice = (
void*) device;
433 mMTLCommandQueue = (
void*) commandQueue;
434 mMTLLayer = pContext;
444#if defined IGRAPHICS_GL
446 mScreenSurface =
nullptr;
447 mGrContext =
nullptr;
448#elif defined IGRAPHICS_METAL
449 [(id<MTLCommandQueue>) mMTLCommandQueue release];
450 mMTLCommandQueue =
nullptr;
452 mMTLDevice =
nullptr;
461#if defined IGRAPHICS_GL || defined IGRAPHICS_METAL
462 if (mGrContext.get())
464 SkImageInfo info = SkImageInfo::MakeN32Premul(w, h);
465 mSurface = SkSurfaces::RenderTarget(mGrContext.get(), skgpu::Budgeted::kYes, info);
471 const size_t bmpSize =
sizeof(BITMAPINFOHEADER) + (w * h *
sizeof(uint32_t));
472 mSurfaceMemory.Resize(bmpSize);
473 BITMAPINFO* bmpInfo =
reinterpret_cast<BITMAPINFO*
>(mSurfaceMemory.Get());
474 ZeroMemory(bmpInfo,
sizeof(BITMAPINFO));
475 bmpInfo->bmiHeader.biSize =
sizeof(BITMAPINFOHEADER);
476 bmpInfo->bmiHeader.biWidth = w;
477 bmpInfo->bmiHeader.biHeight = -h;
478 bmpInfo->bmiHeader.biPlanes = 1;
479 bmpInfo->bmiHeader.biBitCount = 32;
480 bmpInfo->bmiHeader.biCompression = BI_RGB;
481 void* pixels = bmpInfo->bmiColors;
483 SkImageInfo info = SkImageInfo::Make(w, h, kN32_SkColorType, kPremul_SkAlphaType,
nullptr);
484 mSurface = SkSurfaces::WrapPixels(info, pixels,
sizeof(uint32_t) * w);
486 SkImageInfo info = SkImageInfo::MakeN32Premul(w, h);
487 mSurface = SkSurfaces::Raster(info);
492 mCanvas = mSurface->getCanvas();
499#if defined IGRAPHICS_GL
500 if (mGrContext.get())
506 int fbo = 0, samples = 0, stencilBits = 0;
507 glGetIntegerv(GL_FRAMEBUFFER_BINDING, &fbo);
508 glGetIntegerv(GL_SAMPLES, &samples);
510 glGetFramebufferAttachmentParameteriv(GL_DRAW_FRAMEBUFFER, GL_STENCIL, GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE, &stencilBits);
512 glGetIntegerv(GL_STENCIL_BITS, &stencilBits);
515 GrGLFramebufferInfo fbInfo;
517 fbInfo.fFormat = 0x8058;
519 auto backendRT = GrBackendRenderTargets::MakeGL(width, height, samples, stencilBits, fbInfo);
521 mScreenSurface = SkSurfaces::WrapBackendRenderTarget(mGrContext.get(), backendRT, kBottomLeft_GrSurfaceOrigin, kRGBA_8888_SkColorType,
nullptr,
nullptr);
522 assert(mScreenSurface);
524#elif defined IGRAPHICS_METAL
525 if (mGrContext.get())
530 id<CAMetalDrawable> drawable = [(CAMetalLayer*) mMTLLayer nextDrawable];
532 GrMtlTextureInfo fbInfo;
533 fbInfo.fTexture.retain((
const void*)(drawable.texture));
534 auto backendRT = GrBackendRenderTargets::MakeMtl(width, height, fbInfo);
535 mScreenSurface = SkSurfaces::WrapBackendRenderTarget(mGrContext.get(), backendRT, kTopLeft_GrSurfaceOrigin, kBGRA_8888_SkColorType,
nullptr,
nullptr);
537 mMTLDrawable = (
void*) drawable;
538 assert(mScreenSurface);
548 #if defined OS_MAC || defined OS_IOS
550 mSurface->peekPixels(&pixmap);
552 bmp.installPixels(pixmap);
554 CGContextSaveGState(pCGContext);
556 SkCGDrawBitmap(pCGContext, bmp, 0, 0);
557 CGContextRestoreGState(pCGContext);
561 BITMAPINFO* bmpInfo =
reinterpret_cast<BITMAPINFO*
>(mSurfaceMemory.Get());
564 HDC hdc = BeginPaint(hWnd, &ps);
565 StretchDIBits(hdc, 0, 0, w, h, 0, 0, w, h, bmpInfo->bmiColors, bmpInfo, DIB_RGB_COLORS, SRCCOPY);
566 ReleaseDC(hWnd, hdc);
569 #error NOT IMPLEMENTED
572 mSurface->draw(mScreenSurface->getCanvas(), 0.0, 0.0,
nullptr);
574 if (
auto dContext = GrAsDirectContext(mScreenSurface->getCanvas()->recordingContext())) {
575 dContext->flushAndSubmit();
578 #ifdef IGRAPHICS_METAL
579 id<MTLCommandBuffer> commandBuffer = [(id<MTLCommandQueue>) mMTLCommandQueue commandBuffer];
580 commandBuffer.label =
@"Present";
582 [commandBuffer presentDrawable:(id<CAMetalDrawable>) mMTLDrawable];
583 [commandBuffer commit];
592 p.setAntiAlias(
true);
593 p.setBlendMode(SkiaBlendMode(pBlend));
595 p.setAlpha(
Clip(
static_cast<int>(pBlend->mWeight * 255), 0, 255));
603 mCanvas->clipRect(SkiaRect(dest));
604 mCanvas->translate(dest.L, dest.T);
605 mCanvas->scale(scale1, scale1);
606 mCanvas->translate(-srcX * scale2, -srcY * scale2);
609 auto samplingOptions = SkSamplingOptions(SkFilterMode::kLinear, SkMipmapMode::kNone);
611 auto samplingOptions = SkSamplingOptions(SkCubicResampler::Mitchell());
614 if (image->mIsSurface)
615 image->mSurface->draw(mCanvas, 0.0, 0.0, samplingOptions, &p);
617 mCanvas->drawImage(image->mImage, 0.0, 0.0, samplingOptions, &p);
625 arc.setIsVolatile(
true);
627 float sweep = (a2 - a1);
629 if (sweep >= 360.f || sweep <= -360.f)
631 arc.addCircle(cx, cy, r);
632 mMainPath.addPath(arc, mMatrix, SkPath::kAppend_AddPathMode);
636 if (winding == EWinding::CW)
647 arc.arcTo(SkRect::MakeLTRB(cx - r, cy - r, cx + r, cy + r), a1 - 90.f, sweep,
false);
648 mMainPath.addPath(arc, mMatrix, SkPath::kExtend_AddPathMode);
655 bitmap.allocPixels(SkImageInfo::MakeN32Premul(1, 1));
656 mCanvas->readPixels(bitmap, x, y);
657 auto color = bitmap.getColor(0,0);
658 return IColor(SkColorGetA(color), SkColorGetR(color), SkColorGetG(color), SkColorGetB(color));
663 StaticStorage<Font>::Accessor storage(sFontCache);
664 Font* cached = storage.Find(fontID);
669 IFontDataPtr data = font->GetFontData();
673 auto wrappedData = SkData::MakeWithoutCopy(data->Get(), data->GetSize());
674 auto typeFace = SkFontMgrRefDefault()->makeFromData(wrappedData);
677 storage.Add(
new Font(std::move(data), typeFace), fontID);
685void IGraphicsSkia::PrepareAndMeasureText(
const IText& text,
const char* str,
IRECT& r,
double& x,
double & y, SkFont& font)
const
687 SkFontMetrics metrics;
691 StaticStorage<Font>::Accessor storage(sFontCache);
692 Font* pFont = storage.Find(text.mFont);
694 assert(pFont &&
"No font found - did you forget to load it?");
696 font.setTypeface(pFont->mTypeface);
697 font.setHinting(SkFontHinting::kSlight);
698 font.setForceAutoHinting(
false);
699 font.setSubpixel(
true);
700 font.setSize(text.mSize * pFont->mData->GetHeightEMRatio());
703 const double textWidth = font.measureText(str, strlen(str), SkTextEncoding::kUTF8,
nullptr);
704 font.getMetrics(&metrics);
706 const double textHeight = text.mSize;
707 const double ascender = metrics.fAscent;
708 const double descender = metrics.fDescent;
712 case EAlign::Near: x = r.L;
break;
713 case EAlign::Center: x = r.
MW() - (textWidth / 2.0);
break;
714 case EAlign::Far: x = r.R - textWidth;
break;
717 switch (text.mVAlign)
719 case EVAlign::Top: y = r.T - ascender;
break;
720 case EVAlign::Middle: y = r.
MH() - descender + (textHeight / 2.0);
break;
721 case EVAlign::Bottom: y = r.B - descender;
break;
724 r =
IRECT((
float) x, (
float) y + ascender, (
float) (x + textWidth), (
float) (y + ascender + textHeight));
730 font.setEdging(SkFont::Edging::kSubpixelAntiAlias);
734 PrepareAndMeasureText(text, str, bounds, x, y, font);
741 IRECT measured = bounds;
744 font.setEdging(SkFont::Edging::kSubpixelAntiAlias);
748 PrepareAndMeasureText(text, str, measured, x, y, font);
750 DoTextRotation(text, bounds, measured);
752 paint.setColor(SkiaColor(text.mFGColor, pBlend));
753 mCanvas->drawSimpleText(str, strlen(str), SkTextEncoding::kUTF8, x, y, font, paint);
759 SkPaint paint = SkiaPaint(pattern, pBlend);
760 paint.setStyle(SkPaint::kStroke_Style);
762 switch (options.mCapOption)
764 case ELineCap::Butt: paint.setStrokeCap(SkPaint::kButt_Cap);
break;
765 case ELineCap::Round: paint.setStrokeCap(SkPaint::kRound_Cap);
break;
766 case ELineCap::Square: paint.setStrokeCap(SkPaint::kSquare_Cap);
break;
769 switch (options.mJoinOption)
771 case ELineJoin::Miter: paint.setStrokeJoin(SkPaint::kMiter_Join);
break;
772 case ELineJoin::Round: paint.setStrokeJoin(SkPaint::kRound_Join);
break;
773 case ELineJoin::Bevel: paint.setStrokeJoin(SkPaint::kBevel_Join);
break;
776 if (options.mDash.GetCount())
779 int dashCount = options.mDash.GetCount();
780 int dashMax = dashCount & 1 ? dashCount * 2 : dashCount;
783 for (
int i = 0; i < dashMax; i += 2)
785 dashArray[i + 0] = options.mDash.GetArray()[i % dashCount];
786 dashArray[i + 1] = options.mDash.GetArray()[(i + 1) % dashCount];
789 paint.setPathEffect(SkDashPathEffect::Make(dashArray, dashMax, options.mDash.GetOffset()));
792 paint.setStrokeWidth(thickness);
793 paint.setStrokeMiter(options.mMiterLimit);
797 if (!options.mPreserve)
803 SkPaint paint = SkiaPaint(pattern, pBlend);
804 paint.setStyle(SkPaint::kFill_Style);
806 if (options.mFillRule == EFillRule::Winding)
807 mMainPath.setFillType(SkPathFillType::kWinding);
809 mMainPath.setFillType(SkPathFillType::kEvenOdd);
813 if (!options.mPreserve)
817#ifdef IGRAPHICS_DRAWFILL_DIRECT
820 auto paint = SkiaPaint(color, pBlend);
821 paint.setStyle(SkPaint::Style::kStroke_Style);
822 paint.setStrokeWidth(thickness);
823 mCanvas->drawRect(SkiaRect(bounds), paint);
828 auto paint = SkiaPaint(color, pBlend);
829 paint.setStyle(SkPaint::Style::kStroke_Style);
830 paint.setStrokeWidth(thickness);
831 mCanvas->drawRoundRect(SkiaRect(bounds), cornerRadius, cornerRadius, paint);
836 auto paint = SkiaPaint(color, pBlend);
837 paint.setStyle(SkPaint::Style::kStroke_Style);
838 paint.setStrokeWidth(thickness);
839 mCanvas->drawArc(SkRect::MakeLTRB(cx - r, cy - r, cx + r, cy + r), a1 - 90.f, (a2 - a1),
false, paint);
844 auto paint = SkiaPaint(color, pBlend);
845 paint.setStyle(SkPaint::Style::kStroke_Style);
846 paint.setStrokeWidth(thickness);
847 mCanvas->drawCircle(cx, cy, r, paint);
852 auto paint = SkiaPaint(color, pBlend);
853 paint.setStyle(SkPaint::Style::kStroke_Style);
854 paint.setStrokeWidth(thickness);
855 mCanvas->drawOval(SkiaRect(bounds), paint);
860 auto paint = SkiaPaint(color, pBlend);
861 paint.setStyle(SkPaint::Style::kFill_Style);
862 mCanvas->drawRect(SkiaRect(bounds), paint);
867 auto paint = SkiaPaint(color, pBlend);
868 paint.setStyle(SkPaint::Style::kFill_Style);
869 mCanvas->drawRoundRect(SkiaRect(bounds), cornerRadius, cornerRadius, paint);
874 auto paint = SkiaPaint(color, pBlend);
875 paint.setStyle(SkPaint::Style::kFill_Style);
876 mCanvas->drawArc(SkRect::MakeLTRB(cx - r, cy - r, cx + r, cy + r), a1 - 90.f, (a2 - a1),
true, paint);
881 auto paint = SkiaPaint(color, pBlend);
882 paint.setStyle(SkPaint::Style::kFill_Style);
883 mCanvas->drawCircle(cx, cy, r, paint);
888 auto paint = SkiaPaint(color, pBlend);
889 paint.setStyle(SkPaint::Style::kFill_Style);
890 mCanvas->drawOval(SkiaRect(bounds), paint);
894void IGraphicsSkia::RenderPath(SkPaint& paint)
898 if (!mMatrix.isIdentity() && mMatrix.invert(&invMatrix))
901 path.setIsVolatile(
true);
902 mMainPath.transform(invMatrix, &path);
903 mCanvas->drawPath(path, paint);
907 mCanvas->drawPath(mMainPath, paint);
911void IGraphicsSkia::PathTransformSetMatrix(
const IMatrix& m)
913 double xTranslate = 0.0;
914 double yTranslate = 0.0;
919 if (!mLayers.empty())
921 IRECT bounds = mLayers.top()->Bounds();
923 xTranslate = -bounds.L;
924 yTranslate = -bounds.T;
927 mMatrix = SkMatrix::MakeAll(m.mXX, m.mXY, m.mTX, m.mYX, m.mYY, m.mTY, 0, 0, 1);
929 SkMatrix globalMatrix = SkMatrix::Scale(scale, scale);
930 mClipMatrix = SkMatrix();
931 mFinalMatrix = mMatrix;
932 globalMatrix.preTranslate(xTranslate, yTranslate);
933 mClipMatrix.postConcat(globalMatrix);
934 mFinalMatrix.postConcat(globalMatrix);
935 mCanvas->setMatrix(mFinalMatrix);
938void IGraphicsSkia::SetClipRegion(
const IRECT& r)
940 mCanvas->restoreToCount(0);
942 mCanvas->setMatrix(mClipMatrix);
943 mCanvas->clipRect(SkiaRect(r));
944 mCanvas->setMatrix(mFinalMatrix);
949 sk_sp<SkSurface> surface;
950 SkImageInfo info = SkImageInfo::MakeN32Premul(width, height);
952 #ifndef IGRAPHICS_CPU
955 surface = SkSurfaces::Raster(info);
959 surface = SkSurfaces::RenderTarget(mGrContext.get(), skgpu::Budgeted::kYes, info);
962 surface = SkSurfaces::Raster(info);
965 surface->getCanvas()->save();
967 return new Bitmap(std::move(surface), width, height, scale, drawScale);
972 mCanvas = mLayers.empty() ? mSurface->getCanvas() : mLayers.top()->GetAPIBitmap()->GetBitmap()->mSurface->getCanvas();
975static size_t CalcRowBytes(
int width)
977 width = ((width + 7) & (-8));
978 return width *
sizeof(uint32_t);
983 SkiaDrawable* pDrawable = layer->GetAPIBitmap()->GetBitmap();
984 size_t rowBytes = CalcRowBytes(pDrawable->mSurface->width());
985 int size = pDrawable->mSurface->height() *
static_cast<int>(rowBytes);
989 if (data.GetSize() >= size)
991 SkImageInfo info = SkImageInfo::MakeN32Premul(pDrawable->mSurface->width(), pDrawable->mSurface->height());
992 pDrawable->mSurface->readPixels(info, data.Get(), rowBytes, 0, 0);
998 SkiaDrawable* pDrawable = layer->GetAPIBitmap()->GetBitmap();
999 int width = pDrawable->mSurface->width();
1000 int height = pDrawable->mSurface->height();
1001 size_t rowBytes = CalcRowBytes(width);
1002 double scale = layer->GetAPIBitmap()->GetDrawScale() * layer->GetAPIBitmap()->GetScale();
1004 SkCanvas* pCanvas = pDrawable->mSurface->getCanvas();
1009 SkImageInfo info = SkImageInfo::MakeN32Premul(width, height);
1010 SkPixmap pixMap(info, mask.Get(), rowBytes);
1011 sk_sp<SkImage> image = SkImages::RasterFromPixmap(pixMap,
nullptr,
nullptr);
1012 sk_sp<SkImage> foreground;
1016 if (shadow.mDrawForeground)
1017 foreground = pDrawable->mSurface->makeImageSnapshot();
1019 pCanvas->clear(SK_ColorTRANSPARENT);
1021 IBlend blend(EBlend::Default, shadow.mOpacity);
1022 pCanvas->setMatrix(m);
1023 pCanvas->drawImage(image.get(), shadow.mXOffset * scale, shadow.mYOffset * scale);
1024 m = SkMatrix::Scale(scale, scale);
1025 pCanvas->setMatrix(m);
1026 pCanvas->translate(-layer->Bounds().L, -layer->Bounds().T);
1027 SkPaint p = SkiaPaint(shadow.mPattern, &blend);
1028 p.setBlendMode(SkBlendMode::kSrcIn);
1029 pCanvas->drawPaint(p);
1031 if (shadow.mDrawForeground)
1034 pCanvas->setMatrix(m);
1035 pCanvas->drawImage(foreground.get(), 0.0, 0.0);
1041 SkRect r = SkiaRect(innerBounds.
GetTranslated(xyDrop, xyDrop));
1043 SkPaint paint = SkiaPaint(COLOR_BLACK_DROP_SHADOW, pBlend);
1044 paint.setStyle(SkPaint::Style::kFill_Style);
1046 paint.setMaskFilter(SkMaskFilter::MakeBlur(kSolid_SkBlurStyle, blur * 0.5));
1047 mCanvas->drawRoundRect(r, roundness, roundness, paint);
1052#if !defined IGRAPHICS_NO_SKIA_SKPARAGRAPH
1053 using namespace skia::textlayout;
1055 auto ConvertTextAlign = [](EAlign align) {
1058 case EAlign::Near:
return TextAlign::kLeft;
1059 case EAlign::Center:
return TextAlign::kCenter;
1060 case EAlign::Far:
return TextAlign::kRight;
1061 default:
return TextAlign::kLeft;
1065 ParagraphStyle paragraphStyle;
1066 paragraphStyle.setTextAlign(ConvertTextAlign(text.mAlign));
1068 auto builder = ParagraphBuilder::make(paragraphStyle, mFontCollection, GetUnicode());
1070 assert(builder &&
"Paragraph Builder couldn't be created");
1072 TextStyle textStyle;
1073 textStyle.setColor(SkiaColor(text.mFGColor, pBlend));
1075 std::string fontFamily = text.mFont;
1077 size_t pos = fontFamily.find(
'-');
1078 if (pos != std::string::npos)
1080 fontFamily = fontFamily.substr(0, pos);
1083 textStyle.setFontFamilies({SkString(fontFamily)});
1084 textStyle.setFontSize(text.mSize * 0.9);
1085 textStyle.setFontStyle(SkFontStyle(SkFontStyle::kNormal_Weight,
1086 SkFontStyle::kNormal_Width,
1087 SkFontStyle::kUpright_Slant));
1089 builder->pushStyle(textStyle);
1090 builder->addText(str);
1093 auto paragraph = builder->Build();
1095 paragraph->layout(bounds.
W());
1098 switch (text.mVAlign)
1103 case EVAlign::Middle:
1104 yOffset = (bounds.
H() - paragraph->getHeight()) / 2;
1106 case EVAlign::Bottom:
1107 yOffset = bounds.
H() - paragraph->getHeight();
1112 mCanvas->translate(bounds.L, bounds.T + yOffset);
1113 paragraph->paint(mCanvas, 0, 0);
1116 DrawText(text, str, bounds, pBlend);
1123 return "SKIA | CPU";
1124#elif defined IGRAPHICS_GL2
1125 return "SKIA | GL2";
1126#elif defined IGRAPHICS_GL3
1127 return "SKIA | GL3";
1128#elif defined IGRAPHICS_METAL
1129 return "SKIA | Metal";
const void * LoadWinResource(const char *resID, const char *type, int &sizeInBytes, void *pHInstance)
Load a resource from the binary (windows only).
A base class interface for a bitmap abstraction around the different drawing back end bitmap represen...
BitmapData GetBitmap() const
void SetBitmap(BitmapData pBitmap, int w, int h, float scale, float drawScale)
Used to initialise the members after construction.
User-facing bitmap abstraction that you use to manage bitmap data, independant of draw class/platform...
float GetDrawScale() const
APIBitmap * GetAPIBitmap() const
An editor delegate base class that uses IGraphics for the UI.
The lowest level base class of an IGraphics context.
virtual void DrawRect(const IColor &color, const IRECT &bounds, const IBlend *pBlend=0, float thickness=1.f)
Draw a rectangle to the graphics context.
virtual void FillEllipse(const IColor &color, const IRECT &bounds, const IBlend *pBlend=0)
Fill an ellipse within a rectangular region of the graphics context.
virtual void DrawEllipse(const IColor &color, const IRECT &bounds, const IBlend *pBlend=0, float thickness=1.f)
Draw an ellipse within a rectangular region of the graphics context.
void DrawText(const IText &text, const char *str, const IRECT &bounds, const IBlend *pBlend=0)
Draw some text to the graphics context in a specific rectangle.
float GetTotalScale() const
Gets the combined draw and screen/display scaling factor.
virtual void * GetWindow()=0
Get a pointer to the platform view e.g.
virtual void DrawRoundRect(const IColor &color, const IRECT &bounds, float cornerRadius=5.f, const IBlend *pBlend=0, float thickness=1.f)
Draw a rounded rectangle to the graphics context.
void DoMeasureTextRotation(const IText &text, const IRECT &bounds, IRECT &rect) const
int WindowWidth() const
Gets the width of the graphics context including draw scaling.
void PathTransformRestore()
Restore the affine transform of the current path, to the previously saved state.
virtual void FillRect(const IColor &color, const IRECT &bounds, const IBlend *pBlend=0)
Fill a rectangular region of the graphics context with a color.
void * GetPlatformContext()
Get the platform level draw context - an HDC or CGContextRef.
virtual void DrawArc(const IColor &color, float cx, float cy, float r, float a1, float a2, const IBlend *pBlend=0, float thickness=1.f)
Draw an arc to the graphics context.
void RemoveAllControls()
Removes all regular IControls from the control list, as well as special controls (frees memory).
virtual void DrawCircle(const IColor &color, float cx, float cy, float r, const IBlend *pBlend=0, float thickness=1.f)
Draw a circle to the graphics context.
virtual void FillRoundRect(const IColor &color, const IRECT &bounds, float cornerRadius=5.f, const IBlend *pBlend=0)
Fill a rounded rectangle with a color.
virtual void * GetWinModuleHandle()
float GetScreenScale() const
Gets the screen/display scaling factor, e.g.
void PathTransformSave()
Save the current affine transform of the current path.
virtual void FillArc(const IColor &color, float cx, float cy, float r, float a1, float a2, const IBlend *pBlend=0)
Fill an arc segment with a color.
int WindowHeight() const
Gets the height of the graphics context including draw scaling.
virtual void BeginFrame()
Called at the beginning of drawing.
virtual void FillCircle(const IColor &color, float cx, float cy, float r, const IBlend *pBlend=0)
Fill a circle with a color.
APIBitmap * LoadAPIBitmap(const char *fileNameOrResID, int scale, EResourceLocation location, const char *ext) override
Drawing API method to load a bitmap, called internally.
void BeginFrame() override
Called at the beginning of drawing.
void GetLayerBitmapData(const ILayerPtr &layer, RawBitmapData &data) override
Get the contents of a layer as Raw RGBA bitmap data NOTE: you should only call this within IControl::...
void DrawResize() override
void DoDrawText(const IText &text, const char *str, const IRECT &bounds, const IBlend *pBlend) override
void PathStroke(const IPattern &pattern, float thickness, const IStrokeOptions &options, const IBlend *pBlend) override
Stroke the current current path.
void EndFrame() override
Called by some drawing API classes to finally blit the draw bitmap onto the screen or perform other c...
float DoMeasureText(const IText &text, const char *str, IRECT &bounds) const override
void PathArc(float cx, float cy, float r, float a1, float a2, EWinding winding) override
Add an arc to the current path.
void ApplyShadowMask(ILayerPtr &layer, RawBitmapData &mask, const IShadow &shadow) override
Implemented by a graphics backend to apply a calculated shadow mask to a layer, according to the shad...
const char * GetDrawingAPIStr() override
APIBitmap * CreateAPIBitmap(int width, int height, float scale, double drawScale, bool cacheable=false) override
Creates a new API bitmap, either in memory or as a GPU texture.
bool LoadAPIFont(const char *fontID, const PlatformFontPtr &font) override
Drawing API method to load a font from a PlatformFontPtr, called internally.
void OnViewInitialized(void *pContext) override
Called after platform view initialization, so that drawing classes can e.g.
void UpdateLayer() override
Implemented by a graphics backend to prepare for drawing to the layer at the top of the stack.
void DrawMultiLineText(const IText &text, const char *str, const IRECT &bounds, const IBlend *pBlend) override
Draw some multi-line text to the graphics context in a specific rectangle (NanoVG only)
void PathFill(const IPattern &pattern, const IFillOptions &options, const IBlend *pBlend) override
Fill the current current path.
bool BitmapExtSupported(const char *ext) override
Checks a file extension and reports whether this drawing API supports loading that extension.
IColor GetPoint(int x, int y) override
Get the color at an X, Y location in the graphics context.
void DrawBitmap(const IBitmap &bitmap, const IRECT &dest, int srcX, int srcY, const IBlend *pBlend) override
Draw a bitmap (raster) image to the graphics context.
void DrawFastDropShadow(const IRECT &innerBounds, const IRECT &outerBounds, float xyDrop, float roundness, float blur, IBlend *pBlend) override
NanoVG only.
void OnViewDestroyed() override
Called after a platform view is destroyed, so that drawing classes can e.g.
std::unique_ptr< ILayer > ILayerPtr
ILayerPtr is a managed pointer for transferring the ownership of layers.
Used to manage stroke behaviour for path based drawing back ends.
BEGIN_IPLUG_NAMESPACE T Clip(T x, T lo, T hi)
Clips the value x between lo and hi.
static void ToLower(char *cDest, const char *cSrc)
Used to manage composite/blend operations, independent of draw class/platform.
Used to manage color data, independent of draw class/platform.
Used to represent a point/stop in a gradient.
Used to manage fill behaviour.
Used to store transformation matrices.
IMatrix & Invert()
Changes the matrix to be the inverse of its original value.
void TransformPoint(double &x, double &y, double x0, double y0) const
Transforms the point x, y.
Used to store pattern information for gradients.
const IColorStop & GetStop(int idx) const
Get the IColorStop at a particular index (will crash if out of bounds)
Used to manage a rectangular area, independent of draw class/platform.
IRECT GetTranslated(float x, float y) const
Get a translated copy of this rectangle.
Used to specify properties of a drop-shadow to a layer.
IText is used to manage font and text/text entry style for a piece of text on the UI,...