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 | |
33 | namespace os { |
34 | |
35 | SkiaSurface::SkiaSurface() |
36 | : m_surface(nullptr) |
37 | , m_colorSpace(nullptr) |
38 | , m_canvas(nullptr) |
39 | , m_lock(0) |
40 | { |
41 | } |
42 | |
43 | SkiaSurface::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 | |
54 | SkiaSurface::~SkiaSurface() |
55 | { |
56 | ASSERT(m_lock == 0); |
57 | destroy(); |
58 | } |
59 | |
60 | void 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 | |
79 | void 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 | |
98 | void SkiaSurface::destroy() |
99 | { |
100 | if (!m_surface) { |
101 | delete m_canvas; |
102 | m_canvas = nullptr; |
103 | } |
104 | } |
105 | |
106 | void SkiaSurface::flush() const |
107 | { |
108 | if (m_canvas) |
109 | m_canvas->flush(); |
110 | } |
111 | |
112 | void SkiaSurface::flushAndSubmit() const |
113 | { |
114 | if (m_surface) |
115 | m_surface->flushAndSubmit(); |
116 | } |
117 | |
118 | int SkiaSurface::width() const |
119 | { |
120 | if (m_surface) |
121 | return m_surface->width(); |
122 | else |
123 | return m_bitmap.width(); |
124 | } |
125 | |
126 | int SkiaSurface::height() const |
127 | { |
128 | if (m_surface) |
129 | return m_surface->height(); |
130 | else |
131 | return m_bitmap.height(); |
132 | } |
133 | |
134 | const ColorSpaceRef& SkiaSurface::colorSpace() const |
135 | { |
136 | return m_colorSpace; |
137 | } |
138 | |
139 | bool SkiaSurface::isDirectToScreen() const |
140 | { |
141 | return false; |
142 | } |
143 | |
144 | void SkiaSurface::setImmutable() |
145 | { |
146 | if (!m_bitmap.isNull()) |
147 | m_bitmap.setImmutable(); |
148 | } |
149 | |
150 | int SkiaSurface::getSaveCount() const |
151 | { |
152 | return m_canvas->getSaveCount(); |
153 | } |
154 | |
155 | gfx::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 | |
164 | void SkiaSurface::saveClip() |
165 | { |
166 | m_canvas->save(); |
167 | } |
168 | |
169 | void SkiaSurface::restoreClip() |
170 | { |
171 | m_canvas->restore(); |
172 | } |
173 | |
174 | bool SkiaSurface::clipRect(const gfx::Rect& rc) |
175 | { |
176 | m_canvas->clipRect(SkRect::Make(to_skia(rc))); |
177 | return !m_canvas->isClipEmpty(); |
178 | } |
179 | |
180 | void SkiaSurface::save() |
181 | { |
182 | m_canvas->save(); |
183 | } |
184 | |
185 | void SkiaSurface::concat(const gfx::Matrix& matrix) |
186 | { |
187 | m_canvas->concat(matrix.skMatrix()); |
188 | } |
189 | |
190 | void SkiaSurface::setMatrix(const gfx::Matrix& matrix) |
191 | { |
192 | m_canvas->setMatrix(matrix.skMatrix()); |
193 | } |
194 | |
195 | void SkiaSurface::resetMatrix() |
196 | { |
197 | m_canvas->resetMatrix(); |
198 | } |
199 | |
200 | void SkiaSurface::restore() |
201 | { |
202 | m_canvas->restore(); |
203 | } |
204 | |
205 | gfx::Matrix SkiaSurface::matrix() const |
206 | { |
207 | return m_canvas->getTotalMatrix(); |
208 | } |
209 | |
210 | void 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 | |
219 | void SkiaSurface::unlock() |
220 | { |
221 | ASSERT(m_lock > 0); |
222 | if (--m_lock == 0) { |
223 | // m_bitmap is always locked |
224 | } |
225 | } |
226 | |
227 | void 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 | |
251 | void* SkiaSurface::nativeHandle() |
252 | { |
253 | return (void*)this; |
254 | } |
255 | |
256 | void SkiaSurface::clear() |
257 | { |
258 | m_canvas->clear(0); |
259 | } |
260 | |
261 | uint8_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 | |
269 | void 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 | |
328 | gfx::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 | |
352 | void 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 | |
378 | void 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 | |
385 | void 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 | |
397 | void 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 | |
404 | void SkiaSurface::drawPath(const gfx::Path& path, |
405 | const Paint& paint) |
406 | { |
407 | m_canvas->drawPath(path.skPath(), paint.skPaint()); |
408 | } |
409 | |
410 | void 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 | |
448 | void 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 | |
490 | void 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 | |
506 | void 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 | |
526 | void 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 | |
539 | void 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 | |
552 | void 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 | |
581 | void 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 | |
676 | void 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 |
685 | Ref<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 | |
713 | void 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 | |
726 | void 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 | |
740 | void 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 | |
772 | const 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 | |
788 | bool 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 | |