Mercurial > hg > pub > prymula > com
diff DPF-Prymula-audioplugins/dpf/dgl/src/Cairo.cpp @ 3:84e66ea83026
DPF-Prymula-audioplugins-0.231015-2
author | prymula <prymula76@outlook.com> |
---|---|
date | Mon, 16 Oct 2023 21:53:34 +0200 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/DPF-Prymula-audioplugins/dpf/dgl/src/Cairo.cpp Mon Oct 16 21:53:34 2023 +0200 @@ -0,0 +1,827 @@ +/* + * DISTRHO Plugin Framework (DPF) + * Copyright (C) 2012-2022 Filipe Coelho <falktx@falktx.com> + * Copyright (C) 2019-2021 Jean Pierre Cimalando <jp-dev@inbox.ru> + * + * Permission to use, copy, modify, and/or distribute this software for any purpose with + * or without fee is hereby granted, provided that the above copyright notice and this + * permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD + * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER + * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifdef _MSC_VER +// instantiated template classes whose methods are defined elsewhere +# pragma warning(disable:4661) +#endif + +#include "../Cairo.hpp" +#include "../Color.hpp" +#include "../ImageBaseWidgets.hpp" + +#include "SubWidgetPrivateData.hpp" +#include "TopLevelWidgetPrivateData.hpp" +#include "WidgetPrivateData.hpp" +#include "WindowPrivateData.hpp" + +// templated classes +#include "ImageBaseWidgets.cpp" + +START_NAMESPACE_DGL + +// ----------------------------------------------------------------------- + +static void notImplemented(const char* const name) +{ + d_stderr2("cairo function not implemented: %s", name); +} + +// ----------------------------------------------------------------------- +// Color + +void Color::setFor(const GraphicsContext& context, const bool includeAlpha) +{ + cairo_t* const handle = ((const CairoGraphicsContext&)context).handle; + + if (includeAlpha) + cairo_set_source_rgba(handle, red, green, blue, alpha); + else + cairo_set_source_rgb(handle, red, green, blue); +} + +// ----------------------------------------------------------------------- +// Line + +template<typename T> +void Line<T>::draw(const GraphicsContext& context, const T width) +{ + DISTRHO_SAFE_ASSERT_RETURN(posStart != posEnd,); + DISTRHO_SAFE_ASSERT_RETURN(width != 0,); + + cairo_t* const handle = ((const CairoGraphicsContext&)context).handle; + + cairo_set_line_width(handle, width); + cairo_move_to(handle, posStart.getX(), posStart.getY()); + cairo_line_to(handle, posEnd.getX(), posEnd.getY()); + cairo_stroke(handle); +} + +template<typename T> +void Line<T>::draw() +{ + notImplemented("Line::draw"); +} + +template class Line<double>; +template class Line<float>; +template class Line<int>; +template class Line<uint>; +template class Line<short>; +template class Line<ushort>; + +// ----------------------------------------------------------------------- +// Circle + +template<typename T> +static void drawCircle(cairo_t* const handle, + const Point<T>& pos, + const uint numSegments, + const float size, + const float sin, + const float cos, + const bool outline) +{ + DISTRHO_SAFE_ASSERT_RETURN(numSegments >= 3 && size > 0.0f,); + + const T origx = pos.getX(); + const T origy = pos.getY(); + double t, x = size, y = 0.0; + + // TODO use arc + /* + cairo_arc(handle, origx, origy, size, sin, cos); + */ + + cairo_move_to(handle, x + origx, y + origy); + + for (uint i=1; i<numSegments; ++i) + { + cairo_line_to(handle, x + origx, y + origy); + + t = x; + x = cos * x - sin * y; + y = sin * t + cos * y; + } + + cairo_line_to(handle, x + origx, y + origy); + + if (outline) + cairo_stroke(handle); + else + cairo_fill(handle); +} + +template<typename T> +void Circle<T>::draw(const GraphicsContext& context) +{ + cairo_t* const handle = ((const CairoGraphicsContext&)context).handle; + + drawCircle<T>(handle, fPos, fNumSegments, fSize, fSin, fCos, false); +} + +template<typename T> +void Circle<T>::drawOutline(const GraphicsContext& context, const T lineWidth) +{ + DISTRHO_SAFE_ASSERT_RETURN(lineWidth != 0,); + + cairo_t* const handle = ((const CairoGraphicsContext&)context).handle; + + cairo_set_line_width(handle, lineWidth); + drawCircle<T>(handle, fPos, fNumSegments, fSize, fSin, fCos, true); +} + +template<typename T> +void Circle<T>::draw() +{ + notImplemented("Circle::draw"); +} + +template<typename T> +void Circle<T>::drawOutline() +{ + notImplemented("Circle::drawOutline"); +} + +template class Circle<double>; +template class Circle<float>; +template class Circle<int>; +template class Circle<uint>; +template class Circle<short>; +template class Circle<ushort>; + +// ----------------------------------------------------------------------- +// Triangle + +template<typename T> +static void drawTriangle(cairo_t* const handle, + const Point<T>& pos1, + const Point<T>& pos2, + const Point<T>& pos3, + const bool outline) +{ + DISTRHO_SAFE_ASSERT_RETURN(pos1 != pos2 && pos1 != pos3,); + + cairo_move_to(handle, pos1.getX(), pos1.getY()); + cairo_line_to(handle, pos2.getX(), pos2.getY()); + cairo_line_to(handle, pos3.getX(), pos3.getY()); + cairo_line_to(handle, pos1.getX(), pos1.getY()); + + if (outline) + cairo_stroke(handle); + else + cairo_fill(handle); +} + +template<typename T> +void Triangle<T>::draw(const GraphicsContext& context) +{ + cairo_t* const handle = ((const CairoGraphicsContext&)context).handle; + + drawTriangle<T>(handle, pos1, pos2, pos3, false); +} + +template<typename T> +void Triangle<T>::drawOutline(const GraphicsContext& context, const T lineWidth) +{ + DISTRHO_SAFE_ASSERT_RETURN(lineWidth != 0,); + + cairo_t* const handle = ((const CairoGraphicsContext&)context).handle; + + cairo_set_line_width(handle, lineWidth); + drawTriangle<T>(handle, pos1, pos2, pos3, true); +} + +template<typename T> +void Triangle<T>::draw() +{ + notImplemented("Triangle::draw"); +} + +template<typename T> +void Triangle<T>::drawOutline() +{ + notImplemented("Triangle::drawOutline"); +} + +template class Triangle<double>; +template class Triangle<float>; +template class Triangle<int>; +template class Triangle<uint>; +template class Triangle<short>; +template class Triangle<ushort>; + +// ----------------------------------------------------------------------- +// Rectangle + +template<typename T> +static void drawRectangle(cairo_t* const handle, const Rectangle<T>& rect, const bool outline) +{ + cairo_rectangle(handle, rect.getX(), rect.getY(), rect.getWidth(), rect.getHeight()); + + if (outline) + cairo_stroke(handle); + else + cairo_fill(handle); +} + +template<typename T> +void Rectangle<T>::draw(const GraphicsContext& context) +{ + DISTRHO_SAFE_ASSERT_RETURN(isValid(),); + + cairo_t* const handle = ((const CairoGraphicsContext&)context).handle; + + drawRectangle(handle, *this, false); +} + +template<typename T> +void Rectangle<T>::drawOutline(const GraphicsContext& context, const T lineWidth) +{ + DISTRHO_SAFE_ASSERT_RETURN(isValid(),); + DISTRHO_SAFE_ASSERT_RETURN(lineWidth != 0,); + + cairo_t* const handle = ((const CairoGraphicsContext&)context).handle; + + cairo_set_line_width(handle, lineWidth); + drawRectangle(handle, *this, true); +} + +template<typename T> +void Rectangle<T>::draw() +{ + notImplemented("Rectangle::draw"); +} + +template<typename T> +void Rectangle<T>::drawOutline() +{ + notImplemented("Rectangle::drawOutline"); +} + +template class Rectangle<double>; +template class Rectangle<float>; +template class Rectangle<int>; +template class Rectangle<uint>; +template class Rectangle<short>; +template class Rectangle<ushort>; + +// ----------------------------------------------------------------------- +// CairoImage + +static cairo_format_t asCairoImageFormat(const ImageFormat format) noexcept +{ + switch (format) + { + case kImageFormatNull: + break; + case kImageFormatGrayscale: + return CAIRO_FORMAT_A8; + case kImageFormatBGR: + case kImageFormatRGB: + return CAIRO_FORMAT_RGB24; + case kImageFormatBGRA: + case kImageFormatRGBA: + return CAIRO_FORMAT_ARGB32; + } + + return CAIRO_FORMAT_INVALID; +} + +/* +static ImageFormat asCairoImageFormat(const cairo_format_t format) noexcept +{ + switch (format) + { + case CAIRO_FORMAT_INVALID: + break; + case CAIRO_FORMAT_ARGB32: + break; + case CAIRO_FORMAT_RGB24: + break; + case CAIRO_FORMAT_A8: + break; + case CAIRO_FORMAT_A1: + break; + case CAIRO_FORMAT_RGB16_565: + break; + case CAIRO_FORMAT_RGB30: + break; + } + + return kImageFormatNull; +} +*/ + +CairoImage::CairoImage() + : ImageBase(), + surface(nullptr), + surfacedata(nullptr), + datarefcount(nullptr) {} + +CairoImage::CairoImage(const char* const rdata, const uint w, const uint h, const ImageFormat fmt) + : ImageBase(rdata, w, h, fmt), + surface(nullptr), + surfacedata(nullptr), + datarefcount(nullptr) +{ + loadFromMemory(rdata, w, h, fmt); +} + +CairoImage::CairoImage(const char* const rdata, const Size<uint>& s, const ImageFormat fmt) + : ImageBase(rdata, s, fmt), + surface(nullptr), + surfacedata(nullptr), + datarefcount(nullptr) +{ + loadFromMemory(rdata, s, fmt); +} + +CairoImage::CairoImage(const CairoImage& image) + : ImageBase(image.rawData, image.size, image.format), + surface(cairo_surface_reference(image.surface)), + surfacedata(image.surfacedata), + datarefcount(image.datarefcount) +{ + if (datarefcount != nullptr) + ++(*datarefcount); +} + +CairoImage::~CairoImage() +{ + cairo_surface_destroy(surface); + + if (datarefcount != nullptr && --(*datarefcount) == 0) + { + std::free(surfacedata); + std::free(datarefcount); + } +} + +void CairoImage::loadFromMemory(const char* const rdata, const Size<uint>& s, const ImageFormat fmt) noexcept +{ + const cairo_format_t cairoformat = asCairoImageFormat(fmt); + const int width = static_cast<int>(s.getWidth()); + const int height = static_cast<int>(s.getHeight()); + const int stride = cairo_format_stride_for_width(cairoformat, width); + + uchar* const newdata = (uchar*)std::malloc(static_cast<size_t>(width * height * stride * 4)); + DISTRHO_SAFE_ASSERT_RETURN(newdata != nullptr,); + + cairo_surface_t* const newsurface = cairo_image_surface_create_for_data(newdata, cairoformat, width, height, stride); + DISTRHO_SAFE_ASSERT_RETURN(newsurface != nullptr,); + DISTRHO_SAFE_ASSERT_RETURN(static_cast<int>(s.getWidth()) == cairo_image_surface_get_width(newsurface),); + DISTRHO_SAFE_ASSERT_RETURN(static_cast<int>(s.getHeight()) == cairo_image_surface_get_height(newsurface),); + + cairo_surface_destroy(surface); + + if (datarefcount != nullptr && --(*datarefcount) == 0) + std::free(surfacedata); + else + datarefcount = (int*)malloc(sizeof(*datarefcount)); + + surface = newsurface; + surfacedata = newdata; + *datarefcount = 1; + + switch (fmt) + { + case kImageFormatNull: + break; + case kImageFormatGrayscale: + // Grayscale to A8 + // TODO + break; + case kImageFormatBGR: + // BGR8 to CAIRO_FORMAT_RGB24 + for (int h = 0; h < height; ++h) + { + for (int w = 0; w < width; ++w) + { + newdata[h*width*4+w*4+0] = static_cast<uchar>(rdata[h*width*3+w*3+0]); + newdata[h*width*4+w*4+1] = static_cast<uchar>(rdata[h*width*3+w*3+1]); + newdata[h*width*4+w*4+2] = static_cast<uchar>(rdata[h*width*3+w*3+2]); + newdata[h*width*4+w*4+3] = 0; + } + } + break; + case kImageFormatBGRA: + // BGRA8 to CAIRO_FORMAT_ARGB32 + // FIXME something is wrong here... + for (int h = 0, t; h < height; ++h) + { + for (int w = 0; w < width; ++w) + { + if ((t = rdata[h*width*4+w*4+3]) != 0) + { + newdata[h*width*4+w*4+0] = static_cast<uchar>(rdata[h*width*4+w*4+0]); + newdata[h*width*4+w*4+1] = static_cast<uchar>(rdata[h*width*4+w*4+1]); + newdata[h*width*4+w*4+2] = static_cast<uchar>(rdata[h*width*4+w*4+2]); + newdata[h*width*4+w*4+3] = static_cast<uchar>(t); + } + else + { + // make all pixels zero, cairo does not render full transparency otherwise + memset(&newdata[h*width*4+w*4], 0, 4); + } + } + } + break; + case kImageFormatRGB: + // RGB8 to CAIRO_FORMAT_RGB24 + // TODO + break; + case kImageFormatRGBA: + // RGBA8 to CAIRO_FORMAT_ARGB32 + // TODO + break; + } + + ImageBase::loadFromMemory(rdata, s, fmt); +} + +// const GraphicsContext& context +void CairoImage::loadFromPNG(const char* const pngData, const uint pngSize) noexcept +{ + struct PngReaderData + { + const char* dataPtr; + uint sizeLeft; + + static cairo_status_t read(void* const closure, uchar* const data, const uint length) noexcept + { + PngReaderData& readerData = *reinterpret_cast<PngReaderData*>(closure); + + if (readerData.sizeLeft < length) + return CAIRO_STATUS_READ_ERROR; + + std::memcpy(data, readerData.dataPtr, length); + readerData.dataPtr += length; + readerData.sizeLeft -= length; + return CAIRO_STATUS_SUCCESS; + } + }; + + PngReaderData readerData; + readerData.dataPtr = pngData; + readerData.sizeLeft = pngSize; + + cairo_surface_t* const newsurface = cairo_image_surface_create_from_png_stream(PngReaderData::read, &readerData); + DISTRHO_SAFE_ASSERT_RETURN(newsurface != nullptr,); + + const int newwidth = cairo_image_surface_get_width(newsurface); + const int newheight = cairo_image_surface_get_height(newsurface); + DISTRHO_SAFE_ASSERT_INT_RETURN(newwidth > 0, newwidth,); + DISTRHO_SAFE_ASSERT_INT_RETURN(newheight > 0, newheight,); + + cairo_surface_destroy(surface); + + if (datarefcount != nullptr && --(*datarefcount) == 0) + std::free(surfacedata); + else + datarefcount = (int*)malloc(sizeof(*datarefcount)); + + surface = newsurface; + surfacedata = nullptr; // cairo_image_surface_get_data(newsurface); + *datarefcount = 1; + + rawData = nullptr; + format = kImageFormatNull; // asCairoImageFormat(cairo_image_surface_get_format(newsurface)); + size = Size<uint>(static_cast<uint>(newwidth), static_cast<uint>(newheight)); +} + +void CairoImage::drawAt(const GraphicsContext& context, const Point<int>& pos) +{ + if (surface == nullptr) + return; + + cairo_t* const handle = ((const CairoGraphicsContext&)context).handle; + + cairo_set_source_surface(handle, surface, pos.getX(), pos.getY()); + cairo_paint(handle); +} + +CairoImage& CairoImage::operator=(const CairoImage& image) noexcept +{ + cairo_surface_t* newsurface = cairo_surface_reference(image.surface); + cairo_surface_destroy(surface); + + if (datarefcount != nullptr && --(*datarefcount) == 0) + { + std::free(surfacedata); + std::free(datarefcount); + } + + surface = newsurface; + rawData = image.rawData; + size = image.size; + format = image.format; + surfacedata = image.surfacedata; + datarefcount = image.datarefcount; + + if (datarefcount != nullptr) + ++(*datarefcount); + + return *this; +} + +// ----------------------------------------------------------------------- +// CairoSubWidget + +template <> +CairoBaseWidget<SubWidget>::CairoBaseWidget(Widget* const parent) + : SubWidget(parent) {} + +template class CairoBaseWidget<SubWidget>; + +// ----------------------------------------------------------------------- +// CairoTopLevelWidget + +template <> +CairoBaseWidget<TopLevelWidget>::CairoBaseWidget(Window& windowToMapTo) + : TopLevelWidget(windowToMapTo) {} + +template class CairoBaseWidget<TopLevelWidget>; + +// ----------------------------------------------------------------------- +// CairoStandaloneWindow + +template <> +CairoBaseWidget<StandaloneWindow>::CairoBaseWidget(Application& app) + : StandaloneWindow(app) {} + +template <> +CairoBaseWidget<StandaloneWindow>::CairoBaseWidget(Application& app, Window& parentWindow) + : StandaloneWindow(app, parentWindow) {} + +template class CairoBaseWidget<StandaloneWindow>; + +// ----------------------------------------------------------------------- +// ImageBaseAboutWindow + +#if 0 +template <> +void ImageBaseAboutWindow<CairoImage>::onDisplay() +{ + img.draw(getGraphicsContext()); +} +#endif + +template class ImageBaseAboutWindow<CairoImage>; + +// ----------------------------------------------------------------------- +// ImageBaseButton + +template class ImageBaseButton<CairoImage>; + +// ----------------------------------------------------------------------- +// ImageBaseKnob + +template <> +void ImageBaseKnob<CairoImage>::PrivateData::init() +{ + alwaysRepaint = true; + cairoSurface = nullptr; +} + +template <> +void ImageBaseKnob<CairoImage>::PrivateData::cleanup() +{ + cairo_surface_destroy((cairo_surface_t*)cairoSurface); + cairoSurface = nullptr; +} + +/** + Get the pixel size in bytes. + @return pixel size, or 0 if the format is unknown, or pixels are not aligned to bytes. +*/ +static int getBytesPerPixel(const cairo_format_t format) noexcept +{ + switch (format) + { + case CAIRO_FORMAT_ARGB32: + case CAIRO_FORMAT_RGB24: + case CAIRO_FORMAT_RGB30: + return 4; + case CAIRO_FORMAT_RGB16_565: + return 2; + case CAIRO_FORMAT_A8: + return 1; + case CAIRO_FORMAT_A1: + return 0; + default: + DISTRHO_SAFE_ASSERT(false); + return 0; + } +} + +static cairo_surface_t* getRegion(cairo_surface_t* origsurface, int x, int y, int width, int height) noexcept +{ + const cairo_format_t format = cairo_image_surface_get_format(origsurface); + const int bpp = getBytesPerPixel(format); + + if (bpp == 0) + return nullptr; + + const int fullWidth = cairo_image_surface_get_width(origsurface); + const int fullHeight = cairo_image_surface_get_height(origsurface); + const int stride = cairo_image_surface_get_stride(origsurface); + uchar* const fullData = cairo_image_surface_get_data(origsurface); + + x = (x < fullWidth) ? x : fullWidth; + y = (y < fullHeight) ? y : fullHeight; + width = (x + width < fullWidth) ? width : (fullWidth - x); + height = (x + height < fullHeight) ? height : (fullHeight - x); + + uchar* const data = fullData + (x * bpp + y * stride); + return cairo_image_surface_create_for_data(data, format, width, height, stride); +} + +template <> +void ImageBaseKnob<CairoImage>::onDisplay() +{ + const GraphicsContext& context(getGraphicsContext()); + cairo_t* const handle = ((const CairoGraphicsContext&)context).handle; + const double normValue = getNormalizedValue(); + + cairo_surface_t* surface = (cairo_surface_t*)pData->cairoSurface; + + if (! pData->isReady) + { + const int layerW = static_cast<int>(pData->imgLayerWidth); + const int layerH = static_cast<int>(pData->imgLayerHeight); + int layerNum = 0; + + if (pData->rotationAngle == 0) + layerNum = static_cast<int>(normValue * static_cast<double>(pData->imgLayerCount - 1) + 0.5); + + const int layerX = pData->isImgVertical ? 0 : layerNum * layerW; + const int layerY = !pData->isImgVertical ? 0 : layerNum * layerH; + + cairo_surface_t* newsurface; + + if (pData->rotationAngle == 0) + { + newsurface = getRegion(pData->image.getSurface(), layerX, layerY, layerW, layerH); + } + else + { + newsurface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, layerW, layerH); + cairo_t* const cr = cairo_create(newsurface); + cairo_translate(cr, 0.5 * layerW, 0.5 * layerH); + cairo_rotate(cr, normValue * pData->rotationAngle * (M_PI / 180)); + cairo_set_source_surface(cr, pData->image.getSurface(), -0.5 * layerW, -0.5 * layerH); + cairo_paint(cr); + cairo_destroy(cr); + } + + DISTRHO_SAFE_ASSERT_RETURN(newsurface != nullptr,); + + cairo_surface_destroy(surface); + pData->cairoSurface = surface = newsurface; + pData->isReady = true; + } + + if (surface != nullptr) + { + cairo_set_source_surface(handle, surface, 0, 0); + cairo_paint(handle); + } +} + +template class ImageBaseKnob<CairoImage>; + +// ----------------------------------------------------------------------- +// ImageBaseSlider + +template class ImageBaseSlider<CairoImage>; + +// ----------------------------------------------------------------------- +// ImageBaseSwitch + +template class ImageBaseSwitch<CairoImage>; + +// ----------------------------------------------------------------------- + +void SubWidget::PrivateData::display(const uint width, const uint height, const double autoScaleFactor) +{ + cairo_t* const handle = static_cast<const CairoGraphicsContext&>(self->getGraphicsContext()).handle; + + bool needsResetClip = false; + + cairo_matrix_t matrix; + cairo_get_matrix(handle, &matrix); + + if (needsViewportScaling) + { + // limit viewport to widget bounds + // NOTE only used for nanovg for now, which is not relevant here + } + else if (needsFullViewportForDrawing || (absolutePos.isZero() && self->getSize() == Size<uint>(width, height))) + { + // full viewport size + cairo_translate(handle, 0, 0); + cairo_scale(handle, autoScaleFactor, autoScaleFactor); + } + else + { + // set viewport pos + cairo_translate(handle, absolutePos.getX() * autoScaleFactor, absolutePos.getY() * autoScaleFactor); + + // then cut the outer bounds + cairo_rectangle(handle, + 0, + 0, + std::round(self->getWidth() * autoScaleFactor), + std::round(self->getHeight() * autoScaleFactor)); + + cairo_clip(handle); + needsResetClip = true; + + // set viewport scaling + cairo_scale(handle, autoScaleFactor, autoScaleFactor); + } + + // display widget + self->onDisplay(); + + if (needsResetClip) + cairo_reset_clip(handle); + + cairo_set_matrix(handle, &matrix); + + selfw->pData->displaySubWidgets(width, height, autoScaleFactor); +} + +// ----------------------------------------------------------------------- + +void TopLevelWidget::PrivateData::display() +{ + if (! selfw->pData->visible) + return; + + cairo_t* const handle = static_cast<const CairoGraphicsContext&>(self->getGraphicsContext()).handle; + + const Size<uint> size(window.getSize()); + const uint width = size.getWidth(); + const uint height = size.getHeight(); + + const double autoScaleFactor = window.pData->autoScaleFactor; + + cairo_matrix_t matrix; + cairo_get_matrix(handle, &matrix); + + // full viewport size + if (window.pData->autoScaling) + { + cairo_translate(handle, 0, 0); + cairo_scale(handle, autoScaleFactor, autoScaleFactor); + } + else + { + cairo_translate(handle, 0, 0); + cairo_scale(handle, 1.0, 1.0); + } + + // main widget drawing + self->onDisplay(); + + cairo_set_matrix(handle, &matrix); + + // now draw subwidgets if there are any + selfw->pData->displaySubWidgets(width, height, autoScaleFactor); +} + +// ----------------------------------------------------------------------- + +void Window::PrivateData::renderToPicture(const char*, const GraphicsContext&, uint, uint) +{ + notImplemented("Window::PrivateData::renderToPicture"); +} + +// ----------------------------------------------------------------------- + +const GraphicsContext& Window::PrivateData::getGraphicsContext() const noexcept +{ + GraphicsContext& context((GraphicsContext&)graphicsContext); + ((CairoGraphicsContext&)context).handle = (cairo_t*)puglGetContext(view); + return context; +} + +// ----------------------------------------------------------------------- + +END_NAMESPACE_DGL