iPlug2 - C++ Audio Plug-in Framework
Loading...
Searching...
No Matches
IGraphicsCanvas.cpp
1/*
2 ==============================================================================
3
4 This file is part of the iPlug 2 library. Copyright (C) the iPlug 2 developers.
5
6 See LICENSE.txt for more info.
7
8 ==============================================================================
9*/
10
11#include "IGraphicsCanvas.h"
12#include <string>
13#include <utility>
14#include <stdio.h>
15#include <type_traits>
16#include <emscripten.h>
17
18#define STB_IMAGE_IMPLEMENTATION
19#include "stb_image.h"
20#include "wdl_base64.h"
21
22using namespace iplug;
23using namespace igraphics;
24using namespace emscripten;
25
26extern IGraphicsWeb* gGraphics;
27
28extern val GetPreloadedImages();
29extern val GetCanvas();
30
32{
33public:
34 Bitmap(val imageCanvas, const char* name, int scale)
35 {
36 SetBitmap(new val(imageCanvas), imageCanvas["width"].as<int>(), imageCanvas["height"].as<int>(), scale, 1.f);
37 }
38
39 Bitmap(int width, int height, int scale, float drawScale)
40 {
41 val canvas = val::global("document").call<val>("createElement", std::string("canvas"));
42 canvas.set("width", width);
43 canvas.set("height", height);
44
45 SetBitmap(new val(canvas), width, height, scale, drawScale);
46 }
47
48 virtual ~Bitmap()
49 {
50 delete GetBitmap();
51 }
52};
53
54struct IGraphicsCanvas::Font
55{
56 using FontDesc = std::remove_pointer<FontDescriptor>::type;
57
58 Font(FontDesc descriptor, double ascenderRatio, double EMRatio)
59 : mDescriptor(descriptor), mAscenderRatio(ascenderRatio), mEMRatio(EMRatio) {}
60
61 FontDesc mDescriptor;
62 double mAscenderRatio;
63 double mEMRatio;
64};
65
66static std::string GetFontString(const char* fontName, const char* styleName, double size)
67{
68 WDL_String fontString;
69 fontString.SetFormatted(FONT_LEN + 64, "%s %lfpx %s", styleName, size, fontName);
70 return std::string(fontString.Get());
71}
72
73StaticStorage<IGraphicsCanvas::Font> IGraphicsCanvas::sFontCache;
74
75#pragma mark - Utilities
76
77BEGIN_IPLUG_NAMESPACE
78BEGIN_IGRAPHICS_NAMESPACE
79
80std::string CanvasColor(const IColor& color, float alpha)
81{
82 WDL_String str;
83 str.SetFormatted(64, "rgba(%d, %d, %d, %lf)", color.R, color.G, color.B, alpha * color.A / 255.0);
84 return str.Get();
85}
86
87END_IGRAPHICS_NAMESPACE
88END_IPLUG_NAMESPACE
89
90#pragma mark -
91
92IGraphicsCanvas::IGraphicsCanvas(IGEditorDelegate& dlg, int w, int h, int fps, float scale)
93: IGraphics(dlg, w, h, fps, scale)
94{
95 StaticStorage<Font>::Accessor storage(sFontCache);
96 storage.Retain();
97}
98
99IGraphicsCanvas::~IGraphicsCanvas()
100{
101 StaticStorage<Font>::Accessor storage(sFontCache);
102 storage.Release();
103}
104
105void IGraphicsCanvas::DrawBitmap(const IBitmap& bitmap, const IRECT& bounds, int srcX, int srcY, const IBlend* pBlend)
106{
107 val context = GetContext();
108 val img = *bitmap.GetAPIBitmap()->GetBitmap();
109 context.call<void>("save");
110 SetCanvasBlendMode(context, pBlend);
111 context.set("globalAlpha", BlendWeight(pBlend));
112
113 const float bs = bitmap.GetScale();
114 IRECT sr = bounds;
115 sr.Scale(bs * bitmap.GetDrawScale());
116
117 PathRect(bounds);
118 context.call<void>("clip");
119 context.call<void>("drawImage", img, srcX * bs, srcY * bs, sr.W(), sr.H(), bounds.L, bounds.T, bounds.W(), bounds.H());
120 GetContext().call<void>("restore");
121 PathClear();
122}
123
125{
126 GetContext().call<void>("beginPath");
127}
128
130{
131 GetContext().call<void>("closePath");
132}
133
134void IGraphicsCanvas::PathArc(float cx, float cy, float r, float a1, float a2, EWinding winding)
135{
136 GetContext().call<void>("arc", cx, cy, r, DegToRad(a1 - 90.f), DegToRad(a2 - 90.f), winding == EWinding::CCW);
137}
138
139void IGraphicsCanvas::PathMoveTo(float x, float y)
140{
141 GetContext().call<void>("moveTo", x, y);
142}
143
144void IGraphicsCanvas::PathLineTo(float x, float y)
145{
146 GetContext().call<void>("lineTo", x, y);
147}
148
149void IGraphicsCanvas::PathCubicBezierTo(float c1x, float c1y, float c2x, float c2y, float x2, float y2)
150{
151 GetContext().call<void>("bezierCurveTo", c1x, c1y, c2x, c2y, x2, y2);
152}
153
154void IGraphicsCanvas::PathQuadraticBezierTo(float cx, float cy, float x2, float y2)
155{
156 GetContext().call<void>("quadraticCurveTo", cx, cy, x2, y2);
157}
158
159void IGraphicsCanvas::PathStroke(const IPattern& pattern, float thickness, const IStrokeOptions& options, const IBlend* pBlend)
160{
161 val context = GetContext();
162
163 switch (options.mCapOption)
164 {
165 case ELineCap::Butt: context.set("lineCap", "butt"); break;
166 case ELineCap::Round: context.set("lineCap", "round"); break;
167 case ELineCap::Square: context.set("lineCap", "square"); break;
168 }
169
170 switch (options.mJoinOption)
171 {
172 case ELineJoin::Miter: context.set("lineJoin", "miter"); break;
173 case ELineJoin::Round: context.set("lineJoin", "round"); break;
174 case ELineJoin::Bevel: context.set("lineJoin", "bevel"); break;
175 }
176
177 context.set("miterLimit", options.mMiterLimit);
178
179 val dashArray = val::array();
180
181 for (int i = 0; i < options.mDash.GetCount(); i++)
182 dashArray.call<void>("push", val(*(options.mDash.GetArray() + i)));
183
184 context.call<void>("setLineDash", dashArray);
185 context.set("lineDashOffset", options.mDash.GetOffset());
186 context.set("lineWidth", thickness);
187
188 SetCanvasSourcePattern(context, pattern, pBlend);
189
190 context.call<void>("stroke");
191
192 if (!options.mPreserve)
193 PathClear();
194}
195
196void IGraphicsCanvas::PathFill(const IPattern& pattern, const IFillOptions& options, const IBlend* pBlend)
197{
198 val context = GetContext();
199 std::string fillRule(options.mFillRule == EFillRule::Winding ? "nonzero" : "evenodd");
200
201 SetCanvasSourcePattern(context, pattern, pBlend);
202
203 context.call<void>("fill", fillRule);
204
205 if (!options.mPreserve)
206 PathClear();
207}
208
209void IGraphicsCanvas::SetCanvasSourcePattern(val& context, const IPattern& pattern, const IBlend* pBlend)
210{
211 SetCanvasBlendMode(context, pBlend);
212
213 switch (pattern.mType)
214 {
215 case EPatternType::Solid:
216 {
217 const IColor color = pattern.GetStop(0).mColor;
218 std::string colorString = CanvasColor(color, BlendWeight(pBlend));
219
220 context.set("fillStyle", colorString);
221 context.set("strokeStyle", colorString);
222 }
223 break;
224
225 case EPatternType::Linear:
226 case EPatternType::Radial:
227 {
228 double x, y;
229 IMatrix m = IMatrix(pattern.mTransform).Invert();
230 m.TransformPoint(x, y, 0.0, 1.0);
231
232 val gradient = (pattern.mType == EPatternType::Linear) ?
233 context.call<val>("createLinearGradient", m.mTX, m.mTY, x, y) :
234 context.call<val>("createRadialGradient", m.mTX, m.mTY, 0.0, m.mTX, m.mTY, m.mXX);
235
236 for (int i = 0; i < pattern.NStops(); i++)
237 {
238 const IColorStop& stop = pattern.GetStop(i);
239 gradient.call<void>("addColorStop", stop.mOffset, CanvasColor(stop.mColor));
240 }
241
242 context.set("fillStyle", gradient);
243 context.set("strokeStyle", gradient);
244 }
245 break;
246 default:
247 break;
248 }
249}
250
251void IGraphicsCanvas::SetCanvasBlendMode(val& context, const IBlend* pBlend)
252{
253 if (!pBlend)
254 context.set("globalCompositeOperation", "source-over");
255
256 switch (pBlend->mMethod)
257 {
258 case EBlend::SrcOver: context.set("globalCompositeOperation", "source-over"); break;
259 case EBlend::SrcIn: context.set("globalCompositeOperation", "source-in"); break;
260 case EBlend::SrcOut: context.set("globalCompositeOperation", "source-out"); break;
261 case EBlend::SrcAtop: context.set("globalCompositeOperation", "source-atop"); break;
262 case EBlend::DstOver: context.set("globalCompositeOperation", "destination-over"); break;
263 case EBlend::DstIn: context.set("globalCompositeOperation", "destination-in"); break;
264 case EBlend::DstOut: context.set("globalCompositeOperation", "destination-out"); break;
265 case EBlend::DstAtop: context.set("globalCompositeOperation", "destination-atop"); break;
266 case EBlend::Add: context.set("globalCompositeOperation", "lighter"); break;
267 case EBlend::XOR: context.set("globalCompositeOperation", "xor"); break;
268 }
269}
270
271void IGraphicsCanvas::PrepareAndMeasureText(const IText& text, const char* str, IRECT& r, double& x, double & y) const
272{
273 StaticStorage<Font>::Accessor storage(sFontCache);
274 Font* pFont = storage.Find(text.mFont);
275
276 assert(pFont && "No font found - did you forget to load it?");
277
278 FontDescriptor descriptor = &pFont->mDescriptor;
279 val context = GetContext();
280 std::string fontString = GetFontString(descriptor->first.Get(), descriptor->second.Get(), text.mSize * pFont->mEMRatio);
281
282 context.set("font", fontString);
283
284 const double textWidth = context.call<val>("measureText", std::string(str))["width"].as<double>();
285 const double textHeight = text.mSize;
286 const double ascender = pFont->mAscenderRatio * textHeight;
287 const double descender = -(1.0 - pFont->mAscenderRatio) * textHeight;
288
289 switch (text.mAlign)
290 {
291 case EAlign::Near: x = r.L; break;
292 case EAlign::Center: x = r.MW() - (textWidth / 2.0); break;
293 case EAlign::Far: x = r.R - textWidth; break;
294 }
295
296 switch (text.mVAlign)
297 {
298 case EVAlign::Top: y = r.T + ascender; break;
299 case EVAlign::Middle: y = r.MH() + descender + (textHeight / 2.0); break;
300 case EVAlign::Bottom: y = r.B + descender; break;
301 }
302
303 r = IRECT((float) x, (float) (y - ascender), (float) (x + textWidth), (float) (y + textHeight - ascender));
304}
305
306float IGraphicsCanvas::DoMeasureText(const IText& text, const char* str, IRECT& bounds) const
307{
308 IRECT r = bounds;
309 double x, y;
310 PrepareAndMeasureText(text, str, bounds, x, y);
311 DoMeasureTextRotation(text, r, bounds);
312 return bounds.W();
313}
314
315void IGraphicsCanvas::DoDrawText(const IText& text, const char* str, const IRECT& bounds, const IBlend* pBlend)
316{
317 IRECT measured = bounds;
318 val context = GetContext();
319 double x, y;
320
321 PrepareAndMeasureText(text, str, measured, x, y);
323 DoTextRotation(text, bounds, measured);
324 context.set("textBaseline", std::string("alphabetic"));
325 SetCanvasSourcePattern(context, text.mFGColor, pBlend);
326 context.call<void>("fillText", std::string(str), x, y);
328}
329
330void IGraphicsCanvas::PathTransformSetMatrix(const IMatrix& m)
331{
332 const double scale = GetBackingPixelScale();
333 IMatrix t = IMatrix().Scale(scale, scale).Translate(XTranslate(), YTranslate()).Transform(m);
334
335 GetContext().call<void>("setTransform", t.mXX, t.mYX, t.mXY, t.mYY, t.mTX, t.mTY);
336}
337
338void IGraphicsCanvas::SetClipRegion(const IRECT& r)
339{
340 val context = GetContext();
341 context.call<void>("restore");
342 context.call<void>("save");
343 context.call<void>("beginPath");
344 context.call<void>("rect", r.L, r.T, r.W(), r.H());
345 context.call<void>("clip");
346 context.call<void>("beginPath");
347}
348
350{
351 char extLower[32];
352 ToLower(extLower, ext);
353 return (strstr(extLower, "png") != nullptr) || (strstr(extLower, "jpg") != nullptr) || (strstr(extLower, "jpeg") != nullptr);
354}
355
356APIBitmap* IGraphicsCanvas::LoadAPIBitmap(const char* fileNameOrResID, int scale, EResourceLocation location, const char* ext)
357{
358 return new Bitmap(GetPreloadedImages()[fileNameOrResID], fileNameOrResID + 1, scale);
359}
360
361APIBitmap* IGraphicsCanvas::LoadAPIBitmap(const char* name, const void* pData, int dataSize, int scale)
362{
363 int width = 0;
364 int height = 0;
365 int channels = 0;
366 uint8_t* pRGBA;
367
368 pRGBA = stbi_load_from_memory((const uint8_t*)pData, dataSize, &width, &height, &channels, 4);
369 if (!pRGBA)
370 {
371 return nullptr;
372 }
373
374 DBGMSG("Size: %d x %d\n", width, height);
375 // Now that we've decoded the data, put it on a canvas
376 int rgbaSize = width * height * channels;
377 val rgbaArray = val::global("Uint8ClampedArray").new_(val(emscripten::typed_memory_view(rgbaSize, pRGBA)));
378
379 val imgData = val::global("ImageData").new_(rgbaArray, val(width), val(height));
380 val canvas = val::global("document").call<val>("createElement", std::string("canvas"));
381 canvas.set("width", width);
382 canvas.set("height", height);
383
384 val ctx = canvas.call<val>("getContext", std::string("2d"));
385 ctx.call<void>("putImageData", imgData, 0, 0);
386
387 stbi_image_free(pRGBA);
388
389 return new Bitmap(canvas, name, scale);
390}
391
392APIBitmap* IGraphicsCanvas::CreateAPIBitmap(int width, int height, float scale, double drawScale, bool cacheable)
393{
394 return new Bitmap(width, height, scale, drawScale);
395}
396
397void IGraphicsCanvas::GetFontMetrics(const char* font, const char* style, double& ascenderRatio, double& EMRatio)
398{
399 // Provides approximate font metrics for a system font (until text metrics are properly supported)
400 int size = 1000;
401 std::string fontString = GetFontString(font, style, size);
402
403 val document = val::global("document");
404 val textSpan = document.call<val>("createElement", std::string("span"));
405 textSpan.set("innerHTML", std::string("M"));
406 textSpan["style"].set("font", fontString);
407
408 val block = document.call<val>("createElement", std::string("div"));
409 block["style"].set("display", std::string("inline-block"));
410 block["style"].set("width", std::string("1px"));
411 block["style"].set("height", std::string("0px"));
412
413 val div = document.call<val>("createElement", std::string("div"));
414 div.call<void>("appendChild", textSpan);
415 div.call<void>("appendChild", block);
416 document["body"].call<void>("appendChild", div);
417
418 block["style"].set("vertical-align", std::string("baseline"));
419 double ascent = block["offsetTop"].as<double>() - textSpan["offsetTop"].as<double>();
420 double height = textSpan.call<val>("getBoundingClientRect")["height"].as<double>();
421 document["body"].call<void>("removeChild", div);
422
423 EMRatio = size / height;
424 ascenderRatio = ascent / height;
425}
426
427bool IGraphicsCanvas::CompareFontMetrics(const char* style, const char* font1, const char* font2)
428{
429 WDL_String fontCombination;
430 fontCombination.SetFormatted(FONT_LEN * 2 + 2, "%s, %s", font1, font2);
431 val context = GetContext();
432 std::string textString("@BmwdWMoqPYyzZr1234567890.+-=_~'");
433 const int size = 72;
434
435 context.set("font", GetFontString(font2, style, size));
436 val metrics1 = context.call<val>("measureText", textString);
437
438 context.set("font", GetFontString(fontCombination.Get(), style, size));
439 val metrics2 = context.call<val>("measureText", textString);
440
441 return metrics1["width"].as<double>() == metrics2["width"].as<double>();
442}
443
444bool IGraphicsCanvas::FontExists(const char* font, const char* style)
445{
446 return !CompareFontMetrics(style, font, "monospace") || !CompareFontMetrics(style, font, "sans-serif") || !CompareFontMetrics(style, font, "serif");
447}
448
449bool IGraphicsCanvas::LoadAPIFont(const char* fontID, const PlatformFontPtr& font)
450{
451 StaticStorage<Font>::Accessor storage(sFontCache);
452
453 if (storage.Find(fontID))
454 return true;
455
456 if (!font->IsSystem())
457 {
458 IFontDataPtr data = font->GetFontData();
459
460 if (data->IsValid())
461 {
462 // Load the font from data
463
464 val fontData = val(typed_memory_view(data->GetSize(), data->Get()));
465 val fontFace = val::global("FontFace").new_(std::string(fontID), fontData);
466
467 FontDescriptor descriptor = font->GetDescriptor();
468 const double ascenderRatio = data->GetAscender() / static_cast<double>(data->GetAscender() - data->GetDescender());
469 const double EMRatio = data->GetHeightEMRatio();
470 storage.Add(new Font({descriptor->first, descriptor->second}, ascenderRatio, EMRatio), fontID);
471
472 // Add to store and request load immediately
473
474 fontFace.call<val>("load");
475 val::global("document")["fonts"].call<void>("add", fontFace);
476 mLoadingFonts.push_back(fontFace);
477
478 return true;
479 }
480 }
481 else
482 {
483 FontDescriptor descriptor = font->GetDescriptor();
484 const char* fontName = descriptor->first.Get();
485 const char* styleName = descriptor->second.Get();
486
487 if (FontExists(fontName, styleName))
488 {
489 double ascenderRatio, EMRatio;
490
491 GetFontMetrics(descriptor->first.Get(), descriptor->second.Get(), ascenderRatio, EMRatio);
492 storage.Add(new Font({descriptor->first, descriptor->second}, ascenderRatio, EMRatio), fontID);
493 return true;
494 }
495 }
496
497 return false;
498}
499
501{
502 for (auto it = mLoadingFonts.begin(); it != mLoadingFonts.end(); it++)
503 {
504 std::string status = (*it)["status"].as<std::string>();
505
506 if (status.compare("loaded"))
507 {
508 assert(status.compare("error") && "Font didn't load");
509 return false;
510 }
511 }
512
513 mLoadingFonts.clear();
514
515 return true;
516}
517
518void IGraphicsCanvas::GetLayerBitmapData(const ILayerPtr& layer, RawBitmapData& data)
519{
520 const APIBitmap* pBitmap = layer->GetAPIBitmap();
521 int size = pBitmap->GetWidth() * pBitmap->GetHeight() * 4;
522 val context = pBitmap->GetBitmap()->call<val>("getContext", std::string("2d"));
523 val imageData = context.call<val>("getImageData", 0, 0, pBitmap->GetWidth(), pBitmap->GetHeight());
524 val pixelData = imageData["data"];
525 data.Resize(size);
526
527 // Copy pixels from context
528 if (data.GetSize() >= size)
529 {
530 unsigned char* out = data.Get();
531
532 for (auto i = 0; i < size; i++)
533 out[i] = pixelData[i].as<unsigned char>();
534 }
535}
536
537void IGraphicsCanvas::ApplyShadowMask(ILayerPtr& layer, RawBitmapData& mask, const IShadow& shadow)
538{
539 const APIBitmap* pBitmap = layer->GetAPIBitmap();
540 int size = pBitmap->GetWidth() * pBitmap->GetHeight() * 4;
541
542 if (mask.GetSize() >= size)
543 {
544 int width = pBitmap->GetWidth();
545 int height = pBitmap->GetHeight();
546 double scale = pBitmap->GetScale() * pBitmap->GetDrawScale();
547 double x = shadow.mXOffset * scale;
548 double y = shadow.mYOffset * scale;
549 val layerCanvas = *pBitmap->GetBitmap();
550 val layerContext = layerCanvas.call<val>("getContext", std::string("2d"));
551 layerContext.call<void>("setTransform");
552
553 if (!shadow.mDrawForeground)
554 {
555 layerContext.call<void>("clearRect", 0, 0, width, height);
556 }
557
558 Bitmap localBitmap(width, height, pBitmap->GetScale(), pBitmap->GetDrawScale());
559 val localCanvas = *localBitmap.GetBitmap();
560 val localContext = localCanvas.call<val>("getContext", std::string("2d"));
561 val imageData = localContext.call<val>("createImageData", width, height);
562 val pixelData = imageData["data"];
563 unsigned char* in = mask.Get();
564
565 for (auto i = 0; i < size; i++)
566 pixelData.set(i, in[i]);
567
568 localContext.call<void>("putImageData", imageData, 0, 0);
569 IBlend blend(EBlend::SrcIn, shadow.mOpacity);
570 localContext.call<void>("rect", 0, 0, width, height);
571 localContext.call<void>("scale", scale, scale);
572 localContext.call<void>("translate", -(layer->Bounds().L + shadow.mXOffset), -(layer->Bounds().T + shadow.mYOffset));
573 SetCanvasSourcePattern(localContext, shadow.mPattern, &blend);
574 localContext.call<void>("fill");
575
576 layerContext.set("globalCompositeOperation", "destination-over");
577 layerContext.call<void>("drawImage", localCanvas, 0, 0, width, height, x, y, width, height);
578 }
579}
A base class interface for a bitmap abstraction around the different drawing back end bitmap represen...
float GetScale() const
BitmapData GetBitmap() const
void SetBitmap(BitmapData pBitmap, int w, int h, float scale, float drawScale)
Used to initialise the members after construction.
int GetHeight() const
float GetDrawScale() const
int GetWidth() const
User-facing bitmap abstraction that you use to manage bitmap data, independant of draw class/platform...
float GetDrawScale() const
float GetScale() const
APIBitmap * GetAPIBitmap() const
An editor delegate base class for a SOMETHING that uses IGraphics for it's UI.
void PathQuadraticBezierTo(float cx, float cy, float x2, float y2) override
Add a quadratic bezier to the current path from the current point to the specified location.
bool LoadAPIFont(const char *fontID, const PlatformFontPtr &font) override
Drawing API method to load a font from a PlatformFontPtr, called internally.
bool BitmapExtSupported(const char *ext) override
Checks a file extension and reports whether this drawing API supports loading that extension.
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.
APIBitmap * LoadAPIBitmap(const char *fileNameOrResID, int scale, EResourceLocation location, const char *ext) override
Drawing API method to load a bitmap, called internally.
void PathClear() override
Clear the stack of path drawing commands.
void PathCubicBezierTo(float c1x, float c1y, float c2x, float c2y, float x2, float y2) override
Add a cubic bezier to the current path from the current point to the specified location.
void PathClose() override
Close the path that is being specified.
void PathMoveTo(float x, float y) override
Move the current point in the current path.
void PathFill(const IPattern &pattern, const IFillOptions &options, const IBlend *pBlend) override
Fill the current current path.
bool AssetsLoaded() override
Specialized in IGraphicsCanvas drawing backend.
void PathLineTo(float x, float y) override
Add a line to the current path from the current point to the specified location.
void PathStroke(const IPattern &pattern, float thickness, const IStrokeOptions &options, const IBlend *pBlend) override
Stroke the current current path.
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.
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 DoDrawText(const IText &text, const char *str, const IRECT &bounds, const IBlend *pBlend) override
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...
void DrawBitmap(const IBitmap &bitmap, const IRECT &bounds, int srcX, int srcY, const IBlend *pBlend) override
Draw a bitmap (raster) image to the graphics context.
The lowest level base class of an IGraphics context.
Definition: IGraphics.h:86
void PathRect(const IRECT &bounds)
Add a rectangle to the current path.
Definition: IGraphics.cpp:2635
virtual float GetBackingPixelScale() const
Definition: IGraphics.h:1778
void DoMeasureTextRotation(const IText &text, const IRECT &bounds, IRECT &rect) const
Definition: IGraphics.cpp:2227
void PathTransformRestore()
Restore the affine transform of the current path, to the previously saved state.
Definition: IGraphics.cpp:2708
void PathTransformSave()
Save the current affine transform of the current path.
Definition: IGraphics.cpp:2703
IGraphics platform class for the web.
Definition: IGraphicsWeb.h:44
std::unique_ptr< ILayer > ILayerPtr
ILayerPtr is a managed pointer for transferring the ownership of layers.
float BlendWeight(const IBlend *pBlend)
Helper function to extract the blend weight value from an IBlend ptr if it is valid.
Used to manage stroke behaviour for path based drawing back ends.
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 & Scale(float x, float y)
Set the matrix for a scale transform.
IMatrix & Invert()
Changes the matrix to be the inverse of its original value.
IMatrix & Transform(const IRECT &before, const IRECT &after)
IMatrix & Translate(float x, float y)
Set the matrix for a translation transform.
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)
int NStops() const
Used to manage a rectangular area, independent of draw class/platform.
float MH() const
float W() const
void Scale(float scale)
Multiply each field of this IRECT by scale.
float H() const
float MW() const
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,...