1// LAF OS Library
2// Copyright (c) 2018-2022 Igara Studio S.A.
3// Copyright (c) 2016-2018 David Capello
4//
5// This file is released under the terms of the MIT license.
6// Read LICENSE.txt for more information.
7
8#ifdef HAVE_CONFIG_H
9#include "config.h"
10#endif
11
12#include "os/skia/skia_surface.h"
13
14#include "base/file_handle.h"
15#include "gfx/path.h"
16#include "os/skia/skia_helpers.h"
17#include "os/system.h"
18
19#include "include/codec/SkCodec.h"
20#include "include/core/SkCanvas.h"
21#include "include/core/SkColorFilter.h"
22#include "include/core/SkPixelRef.h"
23#include "include/core/SkStream.h"
24#include "include/private/SkColorData.h"
25
26#if SK_SUPPORT_GPU
27 #include "include/gpu/GrDirectContext.h"
28 #include "include/gpu/GrBackendSurface.h"
29#endif
30
31#include <memory>
32
33namespace os {
34
35SkiaSurface::SkiaSurface()
36 : m_surface(nullptr)
37 , m_colorSpace(nullptr)
38 , m_canvas(nullptr)
39 , m_lock(0)
40{
41}
42
43SkiaSurface::SkiaSurface(const sk_sp<SkSurface>& surface)
44 : m_surface(surface)
45 , m_colorSpace(nullptr)
46 , m_canvas(nullptr)
47 , m_lock(0)
48{
49 ASSERT(m_surface);
50 if (m_surface)
51 m_canvas = m_surface->getCanvas();
52}
53
54SkiaSurface::~SkiaSurface()
55{
56 ASSERT(m_lock == 0);
57 destroy();
58}
59
60void SkiaSurface::create(int width, int height, const os::ColorSpaceRef& cs)
61{
62 destroy();
63
64 ASSERT(!m_surface)
65 ASSERT(width > 0);
66 ASSERT(height > 0);
67
68 m_colorSpace = cs;
69
70 SkBitmap bmp;
71 if (!bmp.tryAllocPixels(
72 SkImageInfo::MakeN32(width, height, kOpaque_SkAlphaType, skColorSpace())))
73 throw base::Exception("Cannot create Skia surface");
74
75 bmp.eraseColor(SK_ColorTRANSPARENT);
76 swapBitmap(bmp);
77}
78
79void SkiaSurface::createRgba(int width, int height, const os::ColorSpaceRef& cs)
80{
81 destroy();
82
83 ASSERT(!m_surface);
84 ASSERT(width > 0);
85 ASSERT(height > 0);
86
87 m_colorSpace = cs;
88
89 SkBitmap bmp;
90 if (!bmp.tryAllocPixels(
91 SkImageInfo::MakeN32Premul(width, height, skColorSpace())))
92 throw base::Exception("Cannot create Skia surface");
93
94 bmp.eraseColor(SK_ColorTRANSPARENT);
95 swapBitmap(bmp);
96}
97
98void SkiaSurface::destroy()
99{
100 if (!m_surface) {
101 delete m_canvas;
102 m_canvas = nullptr;
103 }
104}
105
106void SkiaSurface::flush() const
107{
108 if (m_canvas)
109 m_canvas->flush();
110}
111
112void SkiaSurface::flushAndSubmit() const
113{
114 if (m_surface)
115 m_surface->flushAndSubmit();
116}
117
118int SkiaSurface::width() const
119{
120 if (m_surface)
121 return m_surface->width();
122 else
123 return m_bitmap.width();
124}
125
126int SkiaSurface::height() const
127{
128 if (m_surface)
129 return m_surface->height();
130 else
131 return m_bitmap.height();
132}
133
134const ColorSpaceRef& SkiaSurface::colorSpace() const
135{
136 return m_colorSpace;
137}
138
139bool SkiaSurface::isDirectToScreen() const
140{
141 return false;
142}
143
144void SkiaSurface::setImmutable()
145{
146 if (!m_bitmap.isNull())
147 m_bitmap.setImmutable();
148}
149
150int SkiaSurface::getSaveCount() const
151{
152 return m_canvas->getSaveCount();
153}
154
155gfx::Rect SkiaSurface::getClipBounds() const
156{
157 SkIRect rc;
158 if (m_canvas->getDeviceClipBounds(&rc))
159 return gfx::Rect(rc.x(), rc.y(), rc.width(), rc.height());
160 else
161 return gfx::Rect();
162}
163
164void SkiaSurface::saveClip()
165{
166 m_canvas->save();
167}
168
169void SkiaSurface::restoreClip()
170{
171 m_canvas->restore();
172}
173
174bool SkiaSurface::clipRect(const gfx::Rect& rc)
175{
176 m_canvas->clipRect(SkRect::Make(to_skia(rc)));
177 return !m_canvas->isClipEmpty();
178}
179
180void SkiaSurface::save()
181{
182 m_canvas->save();
183}
184
185void SkiaSurface::concat(const gfx::Matrix& matrix)
186{
187 m_canvas->concat(matrix.skMatrix());
188}
189
190void SkiaSurface::setMatrix(const gfx::Matrix& matrix)
191{
192 m_canvas->setMatrix(matrix.skMatrix());
193}
194
195void SkiaSurface::resetMatrix()
196{
197 m_canvas->resetMatrix();
198}
199
200void SkiaSurface::restore()
201{
202 m_canvas->restore();
203}
204
205gfx::Matrix SkiaSurface::matrix() const
206{
207 return m_canvas->getTotalMatrix();
208}
209
210void SkiaSurface::lock()
211{
212 ASSERT(m_lock >= 0);
213 if (m_lock++ == 0) {
214 // TODO add mutex!
215 // m_bitmap is always locked
216 }
217}
218
219void SkiaSurface::unlock()
220{
221 ASSERT(m_lock > 0);
222 if (--m_lock == 0) {
223 // m_bitmap is always locked
224 }
225}
226
227void SkiaSurface::applyScale(int scaleFactor)
228{
229 ASSERT(!m_surface);
230
231 SkBitmap result;
232 if (!result.tryAllocPixels(
233 m_bitmap.info().makeWH(
234 width()*scaleFactor,
235 height()*scaleFactor)))
236 throw base::Exception("Cannot create temporary Skia surface to change scale");
237
238 SkPaint paint;
239 paint.setBlendMode(SkBlendMode::kSrc);
240
241 SkCanvas canvas(result);
242 SkRect srcRect = SkRect::Make(SkIRect::MakeXYWH(0, 0, width(), height()));
243 SkRect dstRect = SkRect::Make(SkIRect::MakeXYWH(0, 0, result.width(), result.height()));
244 canvas.drawImageRect(SkImage::MakeFromRaster(m_bitmap.pixmap(), nullptr, nullptr),
245 srcRect, dstRect, SkSamplingOptions(),
246 &paint, SkCanvas::kStrict_SrcRectConstraint);
247
248 swapBitmap(result);
249}
250
251void* SkiaSurface::nativeHandle()
252{
253 return (void*)this;
254}
255
256void SkiaSurface::clear()
257{
258 m_canvas->clear(0);
259}
260
261uint8_t* SkiaSurface::getData(int x, int y) const
262{
263 if (m_bitmap.isNull())
264 return nullptr;
265 else
266 return (uint8_t*)m_bitmap.getAddr32(x, y);
267}
268
269void SkiaSurface::getFormat(SurfaceFormatData* formatData) const
270{
271 formatData->format = kRgbaSurfaceFormat;
272 formatData->bitsPerPixel = 8*m_bitmap.bytesPerPixel();
273
274 switch (m_bitmap.colorType()) {
275 case kRGB_565_SkColorType:
276 formatData->redShift = SK_R16_SHIFT;
277 formatData->greenShift = SK_G16_SHIFT;
278 formatData->blueShift = SK_B16_SHIFT;
279 formatData->alphaShift = 0;
280 formatData->redMask = SK_R16_MASK;
281 formatData->greenMask = SK_G16_MASK;
282 formatData->blueMask = SK_B16_MASK;
283 formatData->alphaMask = 0;
284 break;
285 case kARGB_4444_SkColorType:
286 formatData->redShift = SK_R4444_SHIFT;
287 formatData->greenShift = SK_G4444_SHIFT;
288 formatData->blueShift = SK_B4444_SHIFT;
289 formatData->alphaShift = SK_A4444_SHIFT;
290 formatData->redMask = (15 << SK_R4444_SHIFT);
291 formatData->greenMask = (15 << SK_G4444_SHIFT);
292 formatData->blueMask = (15 << SK_B4444_SHIFT);
293 formatData->alphaMask = (15 << SK_A4444_SHIFT);
294 break;
295 case kRGBA_8888_SkColorType:
296 formatData->redShift = SK_RGBA_R32_SHIFT;
297 formatData->greenShift = SK_RGBA_G32_SHIFT;
298 formatData->blueShift = SK_RGBA_B32_SHIFT;
299 formatData->alphaShift = SK_RGBA_A32_SHIFT;
300 formatData->redMask = (255 << SK_RGBA_R32_SHIFT);
301 formatData->greenMask = (255 << SK_RGBA_G32_SHIFT);
302 formatData->blueMask = (255 << SK_RGBA_B32_SHIFT);
303 formatData->alphaMask = (255 << SK_RGBA_A32_SHIFT);
304 break;
305 case kBGRA_8888_SkColorType:
306 formatData->redShift = SK_BGRA_R32_SHIFT;
307 formatData->greenShift = SK_BGRA_G32_SHIFT;
308 formatData->blueShift = SK_BGRA_B32_SHIFT;
309 formatData->alphaShift = SK_BGRA_A32_SHIFT;
310 formatData->redMask = (255 << SK_BGRA_R32_SHIFT);
311 formatData->greenMask = (255 << SK_BGRA_G32_SHIFT);
312 formatData->blueMask = (255 << SK_BGRA_B32_SHIFT);
313 formatData->alphaMask = (255 << SK_BGRA_A32_SHIFT);
314 break;
315 default:
316 formatData->redShift = 0;
317 formatData->greenShift = 0;
318 formatData->blueShift = 0;
319 formatData->alphaShift = 0;
320 formatData->redMask = 0;
321 formatData->greenMask = 0;
322 formatData->blueMask = 0;
323 formatData->alphaMask = 0;
324 break;
325 }
326}
327
328gfx::Color SkiaSurface::getPixel(int x, int y) const
329{
330 // Clip input to avoid crash on SkBitmap::getColor()
331 if (x < 0 || y < 0 || x >= width() || y >= height())
332 return 0;
333
334 SkColor c = 0;
335
336 if (m_surface) {
337 SkImageInfo dstInfo = SkImageInfo::MakeN32Premul(1, 1, skColorSpace());
338 uint32_t dstPixels;
339 if (m_canvas->readPixels(dstInfo, &dstPixels, 4, x, y))
340 c = dstPixels;
341 }
342 else
343 c = m_bitmap.getColor(x, y);
344
345 return gfx::rgba(
346 SkColorGetR(c),
347 SkColorGetG(c),
348 SkColorGetB(c),
349 SkColorGetA(c));
350}
351
352void SkiaSurface::putPixel(gfx::Color color, int x, int y)
353{
354 if (m_surface) {
355 m_paint.setColor(to_skia(color));
356 m_canvas->drawPoint(SkIntToScalar(x), SkIntToScalar(y), m_paint);
357 }
358 else {
359 // TODO Find a better way to put a pixel in the same color space
360 // as the internal SkPixmap (as Skia expects a sRGB color
361 // in SkBitmap::erase())
362#if 1
363 auto r = SkIRect::MakeXYWH(x, y, 1, 1);
364 const_cast<SkPixmap&>(m_bitmap.pixmap()).erase(
365 to_skia4f(color),
366 skColorSpace().get(),
367 &r);
368#else
369 // Doesn't work as SkBitmap::erase() expects an sRGB color (and
370 // the color is should be in the same color space as this
371 // surface, so there is no conversion).
372 m_bitmap.erase(to_skia(color),
373 SkIRect::MakeXYWH(x, y, 1, 1));
374#endif
375 }
376}
377
378void SkiaSurface::drawLine(const float x0, const float y0,
379 const float x1, const float y1,
380 const Paint& paint)
381{
382 m_canvas->drawLine(x0, y0, x1, y1, paint.skPaint());
383}
384
385void SkiaSurface::drawRect(const gfx::RectF& rc,
386 const Paint& paint)
387{
388 if (rc.isEmpty())
389 return;
390
391 if (paint.style() == Paint::Style::Stroke)
392 m_canvas->drawRect(to_skia_fix(rc), paint.skPaint());
393 else
394 m_canvas->drawRect(to_skia(rc), paint.skPaint());
395}
396
397void SkiaSurface::drawCircle(const float cx, const float cy,
398 const float radius,
399 const Paint& paint)
400{
401 m_canvas->drawCircle(cx, cy, radius, paint.skPaint());
402}
403
404void SkiaSurface::drawPath(const gfx::Path& path,
405 const Paint& paint)
406{
407 m_canvas->drawPath(path.skPath(), paint.skPaint());
408}
409
410void SkiaSurface::blitTo(Surface* _dst, int srcx, int srcy, int dstx, int dsty, int width, int height) const
411{
412 auto dst = static_cast<SkiaSurface*>(_dst);
413
414 SkRect srcRect = SkRect::MakeXYWH(srcx, srcy, width, height);
415 SkRect dstRect = SkRect::Make(SkIRect::MakeXYWH(dstx, dsty, width, height));
416
417 SkPaint paint;
418 paint.setBlendMode(SkBlendMode::kSrc);
419
420#if SK_SUPPORT_GPU
421 if (auto srcImage = getOrCreateTextureImage()) {
422 dst->m_canvas->drawImageRect(
423 srcImage,
424 srcRect, dstRect,
425 SkSamplingOptions(),
426 &paint, SkCanvas::kStrict_SrcRectConstraint);
427 return;
428 }
429#endif
430
431 if (!m_bitmap.empty()) {
432 dst->m_canvas->drawImageRect(
433 SkImage::MakeFromRaster(m_bitmap.pixmap(), nullptr, nullptr),
434 srcRect, dstRect,
435 SkSamplingOptions(),
436 &paint, SkCanvas::kStrict_SrcRectConstraint);
437 }
438 else {
439 sk_sp<SkImage> snapshot = m_surface->makeImageSnapshot(srcRect.round());
440 srcRect.offsetTo(0, 0);
441 dst->m_canvas->drawImageRect(
442 snapshot, srcRect, dstRect,
443 SkSamplingOptions(),
444 &paint, SkCanvas::kStrict_SrcRectConstraint);
445 }
446}
447
448void SkiaSurface::scrollTo(const gfx::Rect& rc, int dx, int dy)
449{
450 int w = width();
451 int h = height();
452 gfx::Clip clip(rc.x+dx, rc.y+dy, rc);
453 if (!clip.clip(w, h, w, h))
454 return;
455
456 if (m_surface) {
457 SurfaceLock lock(this);
458 blitTo(this, clip.src.x, clip.src.y, clip.dst.x, clip.dst.y, clip.size.w, clip.size.h);
459 return;
460 }
461
462 int bytesPerPixel = m_bitmap.bytesPerPixel();
463 int rowBytes = (int)m_bitmap.rowBytes();
464 int rowDelta;
465
466 if (dy > 0) {
467 clip.src.y += clip.size.h-1;
468 clip.dst.y += clip.size.h-1;
469 rowDelta = -rowBytes;
470 }
471 else
472 rowDelta = rowBytes;
473
474 char* dst = (char*)m_bitmap.getPixels();
475 const char* src = dst;
476 dst += rowBytes*clip.dst.y + bytesPerPixel*clip.dst.x;
477 src += rowBytes*clip.src.y + bytesPerPixel*clip.src.x;
478 w = bytesPerPixel*clip.size.w;
479 h = clip.size.h;
480
481 while (--h >= 0) {
482 memmove(dst, src, w);
483 dst += rowDelta;
484 src += rowDelta;
485 }
486
487 m_bitmap.notifyPixelsChanged();
488}
489
490void SkiaSurface::drawSurface(const Surface* src, int dstx, int dsty)
491{
492 gfx::Clip clip(dstx, dsty, 0, 0, src->width(), src->height());
493 // Don't call clip.clip() and left the clipping to the Skia library
494 // (mainly because Skia knows how to handle clipping even when a
495 // matrix is set).
496
497 SkPaint paint;
498 paint.setBlendMode(SkBlendMode::kSrc);
499 skDrawSurface(
500 src,
501 clip,
502 SkSamplingOptions(),
503 paint);
504}
505
506void SkiaSurface::drawSurface(const Surface* src,
507 const gfx::Rect& srcRect,
508 const gfx::Rect& dstRect,
509 const Sampling& sampling,
510 const os::Paint* paint)
511{
512 SkPaint skSrcPaint;
513 skSrcPaint.setBlendMode(SkBlendMode::kSrc);
514
515 SkSamplingOptions skSampling;
516 to_skia(sampling, skSampling);
517
518 skDrawSurface(
519 src,
520 srcRect,
521 dstRect,
522 skSampling,
523 (paint ? paint->skPaint(): skSrcPaint));
524}
525
526void SkiaSurface::drawRgbaSurface(const Surface* src, int dstx, int dsty)
527{
528 gfx::Clip clip(dstx, dsty, 0, 0, src->width(), src->height());
529
530 SkPaint paint;
531 paint.setBlendMode(SkBlendMode::kSrcOver);
532 skDrawSurface(
533 src,
534 clip,
535 SkSamplingOptions(),
536 paint);
537}
538
539void SkiaSurface::drawRgbaSurface(const Surface* src, int srcx, int srcy, int dstx, int dsty, int w, int h)
540{
541 gfx::Clip clip(dstx, dsty, srcx, srcy, w, h);
542
543 SkPaint paint;
544 paint.setBlendMode(SkBlendMode::kSrcOver);
545 skDrawSurface(
546 src,
547 clip,
548 SkSamplingOptions(),
549 paint);
550}
551
552void SkiaSurface::drawColoredRgbaSurface(const Surface* src, gfx::Color fg, gfx::Color bg, const gfx::Clip& clipbase)
553{
554 gfx::Clip clip(clipbase);
555
556 SkRect srcRect = SkRect::Make(SkIRect::MakeXYWH(clip.src.x, clip.src.y, clip.size.w, clip.size.h));
557 SkRect dstRect = SkRect::Make(SkIRect::MakeXYWH(clip.dst.x, clip.dst.y, clip.size.w, clip.size.h));
558
559 SkPaint paint;
560 paint.setBlendMode(SkBlendMode::kSrcOver);
561
562 if (gfx::geta(bg) > 0) {
563 SkPaint paint;
564 paint.setColor(to_skia(bg));
565 paint.setStyle(SkPaint::kFill_Style);
566 m_canvas->drawRect(dstRect, paint);
567 }
568
569 sk_sp<SkColorFilter> colorFilter(
570 SkColorFilters::Blend(to_skia(fg), SkBlendMode::kSrcIn));
571 paint.setColorFilter(colorFilter);
572
573 skDrawSurface(
574 (SkiaSurface*)src,
575 srcRect,
576 dstRect,
577 SkSamplingOptions(),
578 paint);
579}
580
581void SkiaSurface::drawSurfaceNine(os::Surface* surface,
582 const gfx::Rect& src,
583 const gfx::Rect& center,
584 const gfx::Rect& dst,
585 const bool drawCenter,
586 const os::Paint* paint)
587{
588 SkIRect srcRect = SkIRect::MakeXYWH(src.x, src.y, src.w, src.h);
589 SkRect dstRect = SkRect::Make(SkIRect::MakeXYWH(dst.x, dst.y, dst.w, dst.h));
590
591 SkPaint skPaint;
592 skPaint.setBlendMode(SkBlendMode::kSrcOver);
593 if (paint && paint->color() != gfx::ColorNone) {
594 sk_sp<SkColorFilter> colorFilter(
595 SkColorFilters::Blend(to_skia(paint->color()),
596 SkBlendMode::kSrcIn));
597 skPaint.setColorFilter(colorFilter);
598 }
599
600 int xdivs[2] = { src.x+center.x, src.x+center.x2() };
601 int ydivs[2] = { src.y+center.y, src.y+center.y2() };
602 SkCanvas::Lattice::RectType rectTypes[9] =
603 { SkCanvas::Lattice::kDefault,
604 SkCanvas::Lattice::kDefault,
605 SkCanvas::Lattice::kDefault,
606 SkCanvas::Lattice::kDefault,
607 (drawCenter ? SkCanvas::Lattice::kDefault:
608 SkCanvas::Lattice::kTransparent),
609 SkCanvas::Lattice::kDefault,
610 SkCanvas::Lattice::kDefault,
611 SkCanvas::Lattice::kDefault,
612 SkCanvas::Lattice::kDefault };
613
614 // Without left side
615 if (center.x == 0) {
616 srcRect.fLeft -= 1;
617 dstRect.fLeft -= 1;
618 rectTypes[0] =
619 rectTypes[3] =
620 rectTypes[6] = SkCanvas::Lattice::kTransparent;
621 }
622
623 // Without right side
624 if (center.x2() == src.w) {
625 srcRect.fRight += 1;
626 dstRect.fRight += 1;
627 rectTypes[2] =
628 rectTypes[5] =
629 rectTypes[8] = SkCanvas::Lattice::kTransparent;
630 }
631
632 // Without top side
633 if (center.y == 0) {
634 srcRect.fTop -= 1;
635 dstRect.fTop -= 1;
636 rectTypes[0] =
637 rectTypes[1] =
638 rectTypes[2] = SkCanvas::Lattice::kTransparent;
639 }
640
641 // Without bottom side
642 if (center.y2() == src.h) {
643 srcRect.fBottom += 1;
644 srcRect.fBottom += 1;
645 rectTypes[6] =
646 rectTypes[7] =
647 rectTypes[8] = SkCanvas::Lattice::kTransparent;
648 }
649
650 SkCanvas::Lattice lattice;
651 lattice.fXDivs = xdivs;
652 lattice.fYDivs = ydivs;
653 lattice.fRectTypes = rectTypes;
654 lattice.fXCount = 2;
655 lattice.fYCount = 2;
656 lattice.fBounds = &srcRect;
657 lattice.fColors = nullptr;
658
659#if SK_SUPPORT_GPU
660 if (auto srcImage = ((SkiaSurface*)surface)->getOrCreateTextureImage()) {
661 m_canvas->drawImageLattice(
662 srcImage, lattice, dstRect,
663 SkFilterMode::kNearest,
664 &skPaint);
665 return;
666 }
667#endif
668
669 m_canvas->drawImageLattice(
670 SkImage::MakeFromRaster(((SkiaSurface*)surface)->m_bitmap.pixmap(), nullptr, nullptr).get(),
671 lattice, dstRect,
672 SkFilterMode::kNearest,
673 &skPaint);
674}
675
676void SkiaSurface::swapBitmap(SkBitmap& other)
677{
678 ASSERT(!m_surface);
679 m_bitmap.swap(other);
680 delete m_canvas;
681 m_canvas = new SkCanvas(m_bitmap);
682}
683
684// static
685Ref<Surface> SkiaSurface::loadSurface(const char* filename)
686{
687 FILE* f = base::open_file_raw(filename, "rb");
688 if (!f)
689 return nullptr;
690
691 std::unique_ptr<SkCodec> codec(
692 SkCodec::MakeFromStream(
693 std::unique_ptr<SkFILEStream>(new SkFILEStream(f))));
694 if (!codec)
695 return nullptr;
696
697 SkImageInfo info = codec->getInfo()
698 .makeColorType(kN32_SkColorType)
699 .makeAlphaType(kPremul_SkAlphaType);
700 SkBitmap bm;
701 if (!bm.tryAllocPixels(info))
702 return nullptr;
703
704 const SkCodec::Result r = codec->getPixels(info, bm.getPixels(), bm.rowBytes());
705 if (r != SkCodec::kSuccess)
706 return nullptr;
707
708 auto sur = make_ref<SkiaSurface>();
709 sur->swapBitmap(bm);
710 return sur;
711}
712
713void SkiaSurface::skDrawSurface(
714 const Surface* src,
715 const gfx::Clip& clip,
716 const SkSamplingOptions& sampling,
717 const SkPaint& paint)
718{
719 skDrawSurface(static_cast<const SkiaSurface*>(src),
720 SkRect::MakeXYWH(clip.src.x, clip.src.y, clip.size.w, clip.size.h),
721 SkRect::MakeXYWH(clip.dst.x, clip.dst.y, clip.size.w, clip.size.h),
722 sampling,
723 paint);
724}
725
726void SkiaSurface::skDrawSurface(
727 const Surface* src,
728 const gfx::Rect& srcRect,
729 const gfx::Rect& dstRect,
730 const SkSamplingOptions& sampling,
731 const SkPaint& paint)
732{
733 skDrawSurface(static_cast<const SkiaSurface*>(src),
734 SkRect::MakeXYWH(srcRect.x, srcRect.y, srcRect.w, srcRect.h),
735 SkRect::MakeXYWH(dstRect.x, dstRect.y, dstRect.w, dstRect.h),
736 sampling,
737 paint);
738}
739
740void SkiaSurface::skDrawSurface(
741 const SkiaSurface* src,
742 const SkRect& srcRect,
743 const SkRect& dstRect,
744 const SkSamplingOptions& sampling,
745 const SkPaint& paint)
746{
747#if SK_SUPPORT_GPU
748 src->flush();
749 if (auto srcImage = src->getOrCreateTextureImage()) {
750 m_canvas->drawImageRect(
751 srcImage,
752 srcRect,
753 dstRect,
754 sampling,
755 &paint,
756 SkCanvas::kStrict_SrcRectConstraint);
757 return;
758 }
759#endif
760
761 m_canvas->drawImageRect(
762 SkImage::MakeFromRaster(src->m_bitmap.pixmap(), nullptr, nullptr),
763 srcRect,
764 dstRect,
765 sampling,
766 &paint,
767 SkCanvas::kStrict_SrcRectConstraint);
768}
769
770#if SK_SUPPORT_GPU
771
772const SkImage* SkiaSurface::getOrCreateTextureImage() const
773{
774 // TODO use the GrDirectContext of the specific os::Window
775 auto win = os::instance()->defaultWindow();
776 if (!win || !win->sk_grCtx())
777 return nullptr;
778
779 if (m_image && m_image->isValid(win->sk_grCtx()))
780 return m_image.get();
781 else if (uploadBitmapAsTexture() &&
782 m_image && m_image->isValid(win->sk_grCtx()))
783 return m_image.get();
784 else
785 return nullptr;
786}
787
788bool SkiaSurface::uploadBitmapAsTexture() const
789{
790 SkImageInfo ii = m_bitmap.info();
791 sk_sp<SkImage> image = m_bitmap.asImage();
792
793 Window* win = os::instance()->defaultWindow();
794
795 GrBackendTexture texture;
796 SkImage::BackendTextureReleaseProc proc;
797 SkImage::MakeBackendTextureFromSkImage(
798 win->sk_grCtx(),
799 image,
800 &texture,
801 &proc);
802
803 m_image = SkImage::MakeFromTexture(
804 win->sk_grCtx(),
805 texture,
806 kTopLeft_GrSurfaceOrigin,
807 ii.colorType(),
808 ii.alphaType(),
809 nullptr);
810
811 return (m_image != nullptr);
812}
813
814#endif // SK_SUPPORT_GPU
815
816} // namespace os
817