1 // SHE library
2 // Copyright (C) 2012-2018  David Capello
3 //
4 // This file is released under the terms of the MIT license.
5 // Read LICENSE.txt for more information.
6 
7 #ifndef SHE_SKIA_SKIA_SURFACE_INCLUDED
8 #define SHE_SKIA_SKIA_SURFACE_INCLUDED
9 #pragma once
10 
11 #include "base/exception.h"
12 #include "gfx/clip.h"
13 #include "she/common/generic_surface.h"
14 #include "she/common/sprite_sheet_font.h"
15 
16 #include "SkBitmap.h"
17 #include "SkCanvas.h"
18 #include "SkColorFilter.h"
19 #include "SkColorPriv.h"
20 #include "SkImageInfo.h"
21 #include "SkRegion.h"
22 #include "SkSurface.h"
23 
24 #ifndef SK_BGRA_B32_SHIFT
25   #ifdef SK_CPU_BENDIAN
26     #define SK_BGRA_B32_SHIFT   24
27     #define SK_BGRA_G32_SHIFT   16
28     #define SK_BGRA_R32_SHIFT   8
29     #define SK_BGRA_A32_SHIFT   0
30   #else
31     #define SK_BGRA_B32_SHIFT   0
32     #define SK_BGRA_G32_SHIFT   8
33     #define SK_BGRA_R32_SHIFT   16
34     #define SK_BGRA_A32_SHIFT   24
35   #endif
36 #endif
37 
38 #ifndef SK_A4444_SHIFT
39   #define SK_R4444_SHIFT    12
40   #define SK_G4444_SHIFT    8
41   #define SK_B4444_SHIFT    4
42   #define SK_A4444_SHIFT    0
43 #endif
44 
45 namespace she {
46 
to_skia(gfx::Color c)47 inline SkColor to_skia(gfx::Color c) {
48   return SkColorSetARGBInline(gfx::geta(c), gfx::getr(c), gfx::getg(c), gfx::getb(c));
49 }
50 
to_skia(const gfx::Rect & rc)51 inline SkIRect to_skia(const gfx::Rect& rc) {
52   return SkIRect::MakeXYWH(rc.x, rc.y, rc.w, rc.h);
53 }
54 
55 class SkiaSurface : public Surface {
56 public:
SkiaSurface()57   SkiaSurface() : m_surface(nullptr)
58                 , m_canvas(nullptr)
59                 , m_lock(0) {
60   }
61 
SkiaSurface(const sk_sp<SkSurface> & surface)62   SkiaSurface(const sk_sp<SkSurface>& surface)
63     : m_surface(surface)
64     , m_canvas(nullptr)
65     , m_lock(0)
66   {
67     ASSERT(m_surface);
68     if (m_surface)
69       m_canvas = m_surface->getCanvas();
70   }
71 
~SkiaSurface()72   ~SkiaSurface() {
73     ASSERT(m_lock == 0);
74     if (!m_surface)
75       delete m_canvas;
76   }
77 
create(int width,int height)78   void create(int width, int height) {
79     ASSERT(!m_surface);
80 
81     if (!m_bitmap.tryAllocPixels(
82           SkImageInfo::MakeN32(width, height, kOpaque_SkAlphaType,
83                                colorSpace())))
84       throw base::Exception("Cannot create Skia surface");
85 
86     m_bitmap.eraseColor(SK_ColorTRANSPARENT);
87     rebuild();
88   }
89 
createRgba(int width,int height)90   void createRgba(int width, int height) {
91     ASSERT(!m_surface);
92 
93     if (!m_bitmap.tryAllocPixels(
94           SkImageInfo::MakeN32Premul(width, height, colorSpace())))
95       throw base::Exception("Cannot create Skia surface");
96 
97     m_bitmap.eraseColor(SK_ColorTRANSPARENT);
98     rebuild();
99   }
100 
flush()101   void flush() {
102     if (m_canvas)
103       m_canvas->flush();
104   }
105 
106   // Surface impl
107 
dispose()108   void dispose() override {
109     delete this;
110   }
111 
width()112   int width() const override {
113     if (m_surface)
114       return m_surface->width();
115     else
116       return m_bitmap.width();
117   }
118 
height()119   int height() const override {
120     if (m_surface)
121       return m_surface->height();
122     else
123       return m_bitmap.height();
124   }
125 
isDirectToScreen()126   bool isDirectToScreen() const override {
127     return false;
128   }
129 
getSaveCount()130   int getSaveCount() const override {
131     return m_canvas->getSaveCount();
132   }
133 
getClipBounds()134   gfx::Rect getClipBounds() const override {
135     SkIRect rc;
136     if (m_canvas->getDeviceClipBounds(&rc))
137       return gfx::Rect(rc.x(), rc.y(), rc.width(), rc.height());
138     else
139       return gfx::Rect();
140   }
141 
saveClip()142   void saveClip() override {
143     m_canvas->save();
144   }
145 
restoreClip()146   void restoreClip() override {
147     m_canvas->restore();
148   }
149 
clipRect(const gfx::Rect & rc)150   bool clipRect(const gfx::Rect& rc) override {
151     m_canvas->clipRect(SkRect::Make(to_skia(rc)));
152     return !m_canvas->isClipEmpty();
153   }
154 
setDrawMode(DrawMode mode,int param,const gfx::Color a,const gfx::Color b)155   void setDrawMode(DrawMode mode, int param,
156                    const gfx::Color a,
157                    const gfx::Color b) override {
158     switch (mode) {
159       case DrawMode::Solid:
160         m_paint.setBlendMode(SkBlendMode::kSrcOver);
161         m_paint.setShader(nullptr);
162         break;
163       case DrawMode::Xor:
164         m_paint.setBlendMode(SkBlendMode::kXor);
165         m_paint.setShader(nullptr);
166         break;
167       case DrawMode::Checked: {
168         m_paint.setBlendMode(SkBlendMode::kSrcOver);
169         {
170           SkBitmap bitmap;
171           if (!bitmap.tryAllocPixels(
172                 SkImageInfo::MakeN32(8, 8, kOpaque_SkAlphaType, colorSpace()))) {
173             throw base::Exception("Cannot create temporary Skia surface");
174           }
175 
176           {
177             SkPMColor A = SkPreMultiplyARGB(gfx::geta(a), gfx::getr(a), gfx::getg(a), gfx::getb(a));
178             SkPMColor B = SkPreMultiplyARGB(gfx::geta(b), gfx::getr(b), gfx::getg(b), gfx::getb(b));
179             int offset = 7 - (param & 7);
180             for (int y=0; y<8; y++)
181               for (int x=0; x<8; x++)
182                 *bitmap.getAddr32(x, y) = (((x+y+offset)&7) < 4 ? B: A);
183           }
184 
185           sk_sp<SkShader> shader(
186             SkShader::MakeBitmapShader(
187               bitmap,
188               SkShader::kRepeat_TileMode,
189               SkShader::kRepeat_TileMode));
190           m_paint.setShader(shader);
191         }
192         break;
193       }
194     }
195   }
196 
lock()197   void lock() override {
198     ASSERT(m_lock >= 0);
199     if (m_lock++ == 0) {
200       // m_bitmap is always locked
201     }
202   }
203 
unlock()204   void unlock() override {
205     ASSERT(m_lock > 0);
206     if (--m_lock == 0) {
207       // m_bitmap is always locked
208     }
209   }
210 
applyScale(int scaleFactor)211   void applyScale(int scaleFactor) override {
212     ASSERT(!m_surface);
213 
214     SkBitmap result;
215     if (!result.tryAllocPixels(
216           m_bitmap.info().makeWH(
217             width()*scaleFactor,
218             height()*scaleFactor)))
219       throw base::Exception("Cannot create temporary Skia surface to change scale");
220 
221     SkPaint paint;
222     paint.setBlendMode(SkBlendMode::kSrc);
223 
224     SkCanvas canvas(result);
225     SkRect srcRect = SkRect::Make(SkIRect::MakeXYWH(0, 0, width(), height()));
226     SkRect dstRect = SkRect::Make(SkIRect::MakeXYWH(0, 0, result.width(), result.height()));
227     canvas.drawBitmapRect(m_bitmap, srcRect, dstRect, &paint,
228                           SkCanvas::kStrict_SrcRectConstraint);
229 
230     swapBitmap(result);
231   }
232 
nativeHandle()233   void* nativeHandle() override {
234     return (void*)this;
235   }
236 
clear()237   void clear() override {
238     m_canvas->clear(0);
239   }
240 
getData(int x,int y)241   uint8_t* getData(int x, int y) const override {
242     if (m_bitmap.isNull())
243       return nullptr;
244     else
245       return (uint8_t*)m_bitmap.getAddr32(x, y);
246   }
247 
getFormat(SurfaceFormatData * formatData)248   void getFormat(SurfaceFormatData* formatData) const override {
249     formatData->format = kRgbaSurfaceFormat;
250     formatData->bitsPerPixel = 8*m_bitmap.bytesPerPixel();
251 
252     switch (m_bitmap.colorType()) {
253       case kRGB_565_SkColorType:
254         formatData->redShift   = SK_R16_SHIFT;
255         formatData->greenShift = SK_G16_SHIFT;
256         formatData->blueShift  = SK_B16_SHIFT;
257         formatData->alphaShift = 0;
258         formatData->redMask    = SK_R16_MASK;
259         formatData->greenMask  = SK_G16_MASK;
260         formatData->blueMask   = SK_B16_MASK;
261         formatData->alphaMask  = 0;
262         break;
263       case kARGB_4444_SkColorType:
264         formatData->redShift   = SK_R4444_SHIFT;
265         formatData->greenShift = SK_G4444_SHIFT;
266         formatData->blueShift  = SK_B4444_SHIFT;
267         formatData->alphaShift = SK_A4444_SHIFT;
268         formatData->redMask    = (15 << SK_R4444_SHIFT);
269         formatData->greenMask  = (15 << SK_G4444_SHIFT);
270         formatData->blueMask   = (15 << SK_B4444_SHIFT);
271         formatData->alphaMask  = (15 << SK_A4444_SHIFT);
272         break;
273       case kRGBA_8888_SkColorType:
274         formatData->redShift   = SK_RGBA_R32_SHIFT;
275         formatData->greenShift = SK_RGBA_G32_SHIFT;
276         formatData->blueShift  = SK_RGBA_B32_SHIFT;
277         formatData->alphaShift = SK_RGBA_A32_SHIFT;
278         formatData->redMask    = (255 << SK_RGBA_R32_SHIFT);
279         formatData->greenMask  = (255 << SK_RGBA_G32_SHIFT);
280         formatData->blueMask   = (255 << SK_RGBA_B32_SHIFT);
281         formatData->alphaMask  = (255 << SK_RGBA_A32_SHIFT);
282         break;
283       case kBGRA_8888_SkColorType:
284         formatData->redShift   = SK_BGRA_R32_SHIFT;
285         formatData->greenShift = SK_BGRA_G32_SHIFT;
286         formatData->blueShift  = SK_BGRA_B32_SHIFT;
287         formatData->alphaShift = SK_BGRA_A32_SHIFT;
288         formatData->redMask    = (255 << SK_BGRA_R32_SHIFT);
289         formatData->greenMask  = (255 << SK_BGRA_G32_SHIFT);
290         formatData->blueMask   = (255 << SK_BGRA_B32_SHIFT);
291         formatData->alphaMask  = (255 << SK_BGRA_A32_SHIFT);
292         break;
293       default:
294         formatData->redShift   = 0;
295         formatData->greenShift = 0;
296         formatData->blueShift  = 0;
297         formatData->alphaShift = 0;
298         formatData->redMask    = 0;
299         formatData->greenMask  = 0;
300         formatData->blueMask   = 0;
301         formatData->alphaMask  = 0;
302         break;
303     }
304   }
305 
getPixel(int x,int y)306   gfx::Color getPixel(int x, int y) const override {
307     SkColor c = 0;
308 
309     if (m_surface) {
310       SkImageInfo dstInfo = SkImageInfo::MakeN32Premul(1, 1, colorSpace());
311       uint32_t dstPixels;
312       if (m_canvas->readPixels(dstInfo, &dstPixels, 4, x, y))
313         c = dstPixels;
314     }
315     else
316       c = m_bitmap.getColor(x, y);
317 
318     return gfx::rgba(
319       SkColorGetR(c),
320       SkColorGetG(c),
321       SkColorGetB(c),
322       SkColorGetA(c));
323   }
324 
putPixel(gfx::Color color,int x,int y)325   void putPixel(gfx::Color color, int x, int y) override {
326     m_paint.setColor(to_skia(color));
327     m_canvas->drawPoint(SkIntToScalar(x), SkIntToScalar(y), m_paint);
328   }
329 
drawHLine(gfx::Color color,int x,int y,int w)330   void drawHLine(gfx::Color color, int x, int y, int w) override {
331     m_paint.setColor(to_skia(color));
332     m_canvas->drawLine(
333       SkIntToScalar(x), SkIntToScalar(y),
334       SkIntToScalar(x+w), SkIntToScalar(y), m_paint);
335   }
336 
drawVLine(gfx::Color color,int x,int y,int h)337   void drawVLine(gfx::Color color, int x, int y, int h) override {
338     m_paint.setColor(to_skia(color));
339     m_canvas->drawLine(
340       SkIntToScalar(x), SkIntToScalar(y),
341       SkIntToScalar(x), SkIntToScalar(y+h), m_paint);
342   }
343 
drawLine(gfx::Color color,const gfx::Point & a,const gfx::Point & b)344   void drawLine(gfx::Color color, const gfx::Point& a, const gfx::Point& b) override {
345     m_paint.setColor(to_skia(color));
346     m_canvas->drawLine(
347       SkIntToScalar(a.x), SkIntToScalar(a.y),
348       SkIntToScalar(b.x), SkIntToScalar(b.y), m_paint);
349   }
350 
drawRect(gfx::Color color,const gfx::Rect & rc)351   void drawRect(gfx::Color color, const gfx::Rect& rc) override {
352     m_paint.setColor(to_skia(color));
353     m_paint.setStyle(SkPaint::kStroke_Style);
354     m_canvas->drawIRect(to_skia(gfx::Rect(rc.x, rc.y, rc.w-1, rc.h-1)), m_paint);
355   }
356 
fillRect(gfx::Color color,const gfx::Rect & rc)357   void fillRect(gfx::Color color, const gfx::Rect& rc) override {
358     m_paint.setColor(to_skia(color));
359     m_paint.setStyle(SkPaint::kFill_Style);
360     m_canvas->drawIRect(to_skia(rc), m_paint);
361   }
362 
blitTo(Surface * _dst,int srcx,int srcy,int dstx,int dsty,int width,int height)363   void blitTo(Surface* _dst, int srcx, int srcy, int dstx, int dsty, int width, int height) const override {
364     ASSERT(!m_bitmap.empty());
365 
366     auto dst = static_cast<SkiaSurface*>(_dst);
367 
368     SkIRect srcRect = SkIRect::MakeXYWH(srcx, srcy, width, height);
369     SkRect dstRect = SkRect::Make(SkIRect::MakeXYWH(dstx, dsty, width, height));
370 
371     SkPaint paint;
372     paint.setBlendMode(SkBlendMode::kSrc);
373 
374     dst->m_canvas->drawBitmapRect(m_bitmap, srcRect, dstRect, &paint,
375                                   SkCanvas::kStrict_SrcRectConstraint);
376   }
377 
scrollTo(const gfx::Rect & rc,int dx,int dy)378   void scrollTo(const gfx::Rect& rc, int dx, int dy) override {
379     int w = width();
380     int h = height();
381     gfx::Clip clip(rc.x+dx, rc.y+dy, rc);
382     if (!clip.clip(w, h, w, h))
383       return;
384 
385     if (m_surface) {
386       SurfaceLock lock(this);
387       blitTo(this, clip.src.x, clip.src.y, clip.dst.x, clip.dst.y, clip.size.w, clip.size.h);
388       return;
389     }
390 
391     int bytesPerPixel = m_bitmap.bytesPerPixel();
392     int rowBytes = (int)m_bitmap.rowBytes();
393     int rowDelta;
394 
395     if (dy > 0) {
396       clip.src.y += clip.size.h-1;
397       clip.dst.y += clip.size.h-1;
398       rowDelta = -rowBytes;
399     }
400     else
401       rowDelta = rowBytes;
402 
403     char* dst = (char*)m_bitmap.getPixels();
404     const char* src = dst;
405     dst += rowBytes*clip.dst.y + bytesPerPixel*clip.dst.x;
406     src += rowBytes*clip.src.y + bytesPerPixel*clip.src.x;
407     w = bytesPerPixel*clip.size.w;
408     h = clip.size.h;
409 
410     while (--h >= 0) {
411       memmove(dst, src, w);
412       dst += rowDelta;
413       src += rowDelta;
414     }
415 
416     m_bitmap.notifyPixelsChanged();
417   }
418 
drawSurface(const Surface * src,int dstx,int dsty)419   void drawSurface(const Surface* src, int dstx, int dsty) override {
420     gfx::Clip clip(dstx, dsty, 0, 0,
421       ((SkiaSurface*)src)->width(),
422       ((SkiaSurface*)src)->height());
423 
424     if (!clip.clip(width(), height(), clip.size.w, clip.size.h))
425       return;
426 
427     SkRect srcRect = SkRect::Make(SkIRect::MakeXYWH(clip.src.x, clip.src.y, clip.size.w, clip.size.h));
428     SkRect dstRect = SkRect::Make(SkIRect::MakeXYWH(clip.dst.x, clip.dst.y, clip.size.w, clip.size.h));
429 
430     SkPaint paint;
431     paint.setBlendMode(SkBlendMode::kSrc);
432 
433     m_canvas->drawBitmapRect(
434       ((SkiaSurface*)src)->m_bitmap, srcRect, dstRect, &paint,
435       SkCanvas::kStrict_SrcRectConstraint);
436   }
437 
drawRgbaSurface(const Surface * src,int dstx,int dsty)438   void drawRgbaSurface(const Surface* src, int dstx, int dsty) override {
439     gfx::Clip clip(dstx, dsty, 0, 0,
440       ((SkiaSurface*)src)->width(),
441       ((SkiaSurface*)src)->height());
442 
443     if (!clip.clip(width(), height(), clip.size.w, clip.size.h))
444       return;
445 
446     SkRect srcRect = SkRect::Make(SkIRect::MakeXYWH(clip.src.x, clip.src.y, clip.size.w, clip.size.h));
447     SkRect dstRect = SkRect::Make(SkIRect::MakeXYWH(clip.dst.x, clip.dst.y, clip.size.w, clip.size.h));
448 
449     SkPaint paint;
450     paint.setBlendMode(SkBlendMode::kSrcOver);
451 
452     m_canvas->drawBitmapRect(
453       ((SkiaSurface*)src)->m_bitmap, srcRect, dstRect, &paint,
454       SkCanvas::kStrict_SrcRectConstraint);
455   }
456 
drawRgbaSurface(const Surface * src,int srcx,int srcy,int dstx,int dsty,int w,int h)457   void drawRgbaSurface(const Surface* src, int srcx, int srcy, int dstx, int dsty, int w, int h) override {
458     gfx::Clip clip(dstx, dsty, srcx, srcy, w, h);
459     if (!clip.clip(width(), height(), src->width(), src->height()))
460       return;
461 
462     SkRect srcRect = SkRect::Make(SkIRect::MakeXYWH(clip.src.x, clip.src.y, clip.size.w, clip.size.h));
463     SkRect dstRect = SkRect::Make(SkIRect::MakeXYWH(clip.dst.x, clip.dst.y, clip.size.w, clip.size.h));
464 
465     SkPaint paint;
466     paint.setBlendMode(SkBlendMode::kSrcOver);
467 
468     m_canvas->drawBitmapRect(
469       ((SkiaSurface*)src)->m_bitmap, srcRect, dstRect, &paint,
470       SkCanvas::kStrict_SrcRectConstraint);
471   }
472 
drawRgbaSurface(const Surface * src,const gfx::Rect & srcRect,const gfx::Rect & dstRect)473   void drawRgbaSurface(const Surface* src, const gfx::Rect& srcRect, const gfx::Rect& dstRect) override {
474     SkRect srcRect2 = SkRect::Make(SkIRect::MakeXYWH(srcRect.x, srcRect.y, srcRect.w, srcRect.h));
475     SkRect dstRect2 = SkRect::Make(SkIRect::MakeXYWH(dstRect.x, dstRect.y, dstRect.w, dstRect.h));
476 
477     SkPaint paint;
478     paint.setBlendMode(SkBlendMode::kSrcOver);
479     paint.setFilterQuality(srcRect.w < dstRect.w ||
480                            srcRect.h < dstRect.h ? kNone_SkFilterQuality:
481                                                    kHigh_SkFilterQuality);
482 
483     m_canvas->drawBitmapRect(
484       ((SkiaSurface*)src)->m_bitmap, srcRect2, dstRect2, &paint,
485       SkCanvas::kStrict_SrcRectConstraint);
486   }
487 
drawColoredRgbaSurface(const Surface * src,gfx::Color fg,gfx::Color bg,const gfx::Clip & clipbase)488   void drawColoredRgbaSurface(const Surface* src, gfx::Color fg, gfx::Color bg, const gfx::Clip& clipbase) override {
489     gfx::Clip clip(clipbase);
490     if (!clip.clip(width(), height(), src->width(), src->height()))
491       return;
492 
493     SkRect srcRect = SkRect::Make(SkIRect::MakeXYWH(clip.src.x, clip.src.y, clip.size.w, clip.size.h));
494     SkRect dstRect = SkRect::Make(SkIRect::MakeXYWH(clip.dst.x, clip.dst.y, clip.size.w, clip.size.h));
495 
496     SkPaint paint;
497     paint.setBlendMode(SkBlendMode::kSrcOver);
498 
499     if (gfx::geta(bg) > 0) {
500       SkPaint paint;
501       paint.setColor(to_skia(bg));
502       paint.setStyle(SkPaint::kFill_Style);
503       m_canvas->drawRect(dstRect, paint);
504     }
505 
506     sk_sp<SkColorFilter> colorFilter(
507       SkColorFilter::MakeModeFilter(to_skia(fg), SkBlendMode::kSrcIn));
508     paint.setColorFilter(colorFilter);
509 
510     m_canvas->drawBitmapRect(
511       ((SkiaSurface*)src)->m_bitmap,
512       srcRect, dstRect, &paint);
513   }
514 
bitmap()515   SkBitmap& bitmap() {
516     return m_bitmap;
517   }
518 
swapBitmap(SkBitmap & other)519   void swapBitmap(SkBitmap& other) {
520     ASSERT(!m_surface);
521 
522     m_bitmap.swap(other);
523     rebuild();
524   }
525 
526   static Surface* loadSurface(const char* filename);
527 
528 private:
rebuild()529   void rebuild() {
530     ASSERT(!m_surface);
531 
532     delete m_canvas;
533     m_canvas = new SkCanvas(m_bitmap);
534   }
535 
536   static sk_sp<SkColorSpace> colorSpace();
537 
538   SkBitmap m_bitmap;
539   sk_sp<SkSurface> m_surface;
540   SkCanvas* m_canvas;
541   SkPaint m_paint;
542   int m_lock;
543   static sk_sp<SkColorSpace> m_colorSpace;
544 
545 };
546 
547 } // namespace she
548 
549 #endif
550