// SPDX-License-Identifier: GPL-2.0-or-later /** * @file * Cairo drawing context with Inkscape extensions. *//* * Authors: * Krzysztof KosiƄski * * Copyright (C) 2011 Authors * Released under GNU GPL v2+, read the file 'COPYING' for more information. */ #include "display/drawing-context.h" #include "display/drawing-surface.h" #include "display/cairo-utils.h" namespace Inkscape { using Geom::X; using Geom::Y; /** * @class DrawingContext::Save * RAII idiom for saving the state of DrawingContext. */ DrawingContext::Save::Save() : _dc(nullptr) {} DrawingContext::Save::Save(DrawingContext &dc) : _dc(&dc) { _dc->save(); } DrawingContext::Save::~Save() { if (_dc) { _dc->restore(); } } void DrawingContext::Save::save(DrawingContext &dc) { if (_dc) { // TODO: it might be better to treat this occurrence as a bug _dc->restore(); } _dc = &dc; _dc->save(); } /** * @class DrawingContext * Minimal wrapper over Cairo. * * This is a wrapper over cairo_t, extended with operations that work * with 2Geom geometrical primitives. Some of this is probably duplicated * in cairo-render-context.cpp, which provides higher level operations * for drawing entire SPObjects when exporting. */ // Uses existing Cairo surface DrawingContext::DrawingContext(cairo_t *ct, Geom::Point const &origin) : _ct(ct) , _surface(new DrawingSurface(cairo_get_group_target(ct), origin)) , _delete_surface(true) , _restore_context(true) { _surface->_has_context = true; cairo_reference(_ct); cairo_save(_ct); cairo_translate(_ct, -origin[Geom::X], -origin[Geom::Y]); } // Uses existing Cairo surface DrawingContext::DrawingContext(cairo_surface_t *surface, Geom::Point const &origin) : _ct(nullptr) , _surface(new DrawingSurface(surface, origin)) , _delete_surface(true) , _restore_context(false) { _surface->_has_context = true; _ct = _surface->createRawContext(); } DrawingContext::DrawingContext(DrawingSurface &s) : _ct(s.createRawContext()) , _surface(&s) , _delete_surface(false) , _restore_context(false) {} DrawingContext::~DrawingContext() { if (_restore_context) { cairo_restore(_ct); } cairo_destroy(_ct); _surface->_has_context = false; if (_delete_surface) { delete _surface; } } void DrawingContext::arc(Geom::Point const ¢er, double radius, Geom::AngleInterval const &angle) { double from = angle.initialAngle(); double to = angle.finalAngle(); if (to > from) { cairo_arc(_ct, center[X], center[Y], radius, from, to); } else { cairo_arc_negative(_ct, center[X], center[Y], radius, to, from); } } // Applies transform to Cairo surface void DrawingContext::transform(Geom::Affine const &trans) { ink_cairo_transform(_ct, trans); } void DrawingContext::path(Geom::PathVector const &pv) { feed_pathvector_to_cairo(_ct, pv); } void DrawingContext::paint(double alpha) { if (alpha == 1.0) cairo_paint(_ct); else cairo_paint_with_alpha(_ct, alpha); } void DrawingContext::setHairline() { ink_cairo_set_hairline(_ct); } void DrawingContext::setSource(guint32 rgba) { ink_cairo_set_source_rgba32(_ct, rgba); } void DrawingContext::setSource(DrawingSurface *s) { Geom::Point origin = s->origin(); cairo_set_source_surface(_ct, s->raw(), origin[X], origin[Y]); } void DrawingContext::setSourceCheckerboard() { cairo_pattern_t *check = ink_cairo_pattern_create_checkerboard(); cairo_set_source(_ct, check); cairo_pattern_destroy(check); } Geom::Rect DrawingContext::targetLogicalBounds() const { Geom::Rect ret(_surface->area()); return ret; } } // end namespace Inkscape /* Local Variables: mode:c++ c-file-style:"stroustrup" c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) indent-tabs-mode:nil fill-column:99 End: */ // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :