| 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 | |