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