1 | // LAF OS Library |
2 | // Copyright (C) 2020-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_window_x11.h" |
13 | |
14 | #include "gfx/size.h" |
15 | #include "os/event.h" |
16 | #include "os/event_queue.h" |
17 | #include "os/gl/gl_context_glx.h" |
18 | #include "os/skia/skia_surface.h" |
19 | #include "os/skia/skia_window.h" |
20 | #include "os/system.h" |
21 | #include "os/x11/x11.h" |
22 | |
23 | #include "include/core/SkBitmap.h" |
24 | |
25 | namespace os { |
26 | |
27 | namespace { |
28 | |
29 | bool convert_skia_bitmap_to_ximage(const SkBitmap& bitmap, XImage& image) |
30 | { |
31 | memset(&image, 0, sizeof(image)); |
32 | int bpp = 8*bitmap.bytesPerPixel(); |
33 | image.width = bitmap.width(); |
34 | image.height = bitmap.height(); |
35 | image.format = ZPixmap; |
36 | image.data = (char*)bitmap.getPixels(); |
37 | image.byte_order = LSBFirst; |
38 | image.bitmap_unit = bpp; |
39 | image.bitmap_bit_order = LSBFirst; |
40 | image.bitmap_pad = bpp; |
41 | image.depth = (bitmap.alphaType() == kPremul_SkAlphaType ? 32: 24); |
42 | image.bytes_per_line = bitmap.rowBytes() - 4*bitmap.width(); |
43 | image.bits_per_pixel = bpp; |
44 | |
45 | return (XInitImage(&image) ? true: false); |
46 | } |
47 | |
48 | } // anonymous namespace |
49 | |
50 | SkiaWindowX11::SkiaWindowX11(const WindowSpec& spec) |
51 | : Base(X11::instance()->display(), spec) |
52 | { |
53 | #if SK_SUPPORT_GPU |
54 | m_glCtx = std::make_unique<GLContextGLX>(x11display(), x11window()); |
55 | #endif |
56 | initColorSpace(); |
57 | } |
58 | |
59 | void SkiaWindowX11::onPaint(const gfx::Rect& rc) |
60 | { |
61 | #if SK_SUPPORT_GPU |
62 | if (backend() == Backend::GL) |
63 | return; |
64 | #endif |
65 | |
66 | auto surface = static_cast<SkiaSurface*>(this->surface()); |
67 | const SkBitmap& bitmap = surface->bitmap(); |
68 | |
69 | int scale = this->scale(); |
70 | if (scale == 1) { |
71 | XImage image; |
72 | if (convert_skia_bitmap_to_ximage(bitmap, image)) { |
73 | XPutImage( |
74 | x11display(), x11window(), gc(), &image, |
75 | rc.x, rc.y, |
76 | rc.x, rc.y, |
77 | rc.w, rc.h); |
78 | } |
79 | } |
80 | else { |
81 | SkBitmap scaled; |
82 | const SkImageInfo info = |
83 | SkImageInfo::Make(rc.w, rc.h, |
84 | bitmap.info().colorType(), |
85 | bitmap.info().alphaType()); |
86 | |
87 | // Increase m_buffer for "scaled" pixels if needed. |
88 | const size_t rowBytes = info.minRowBytes(); |
89 | const size_t requiredSize = info.computeByteSize(rowBytes); |
90 | if (requiredSize > m_buffer.size()) |
91 | m_buffer.resize(requiredSize); |
92 | |
93 | if (scaled.installPixels(info, (void*)&m_buffer[0], rowBytes)) { |
94 | SkPaint paint; |
95 | paint.setBlendMode(SkBlendMode::kSrc); |
96 | |
97 | SkCanvas canvas(scaled); |
98 | SkRect srcRect = SkRect::Make(SkIRect::MakeXYWH(rc.x/scale, rc.y/scale, rc.w/scale, rc.h/scale)); |
99 | SkRect dstRect = SkRect::Make(SkIRect::MakeXYWH(0, 0, rc.w, rc.h)); |
100 | canvas.drawImageRect(SkImage::MakeFromRaster(bitmap.pixmap(), nullptr, nullptr), |
101 | srcRect, dstRect, SkSamplingOptions(), |
102 | &paint, SkCanvas::kStrict_SrcRectConstraint); |
103 | |
104 | XImage image; |
105 | if (convert_skia_bitmap_to_ximage(scaled, image)) { |
106 | XPutImage( |
107 | x11display(), x11window(), gc(), &image, |
108 | 0, 0, |
109 | rc.x, rc.y, |
110 | rc.w, rc.h); |
111 | } |
112 | } |
113 | } |
114 | } |
115 | |
116 | } // namespace os |
117 | |