22#ifndef PANGO_ENABLE_BACKEND
23#define PANGO_ENABLE_BACKEND
26#ifndef PANGO_ENABLE_ENGINE
27#define PANGO_ENABLE_ENGINE
40#include <glibmm/i18n.h>
43#ifdef CAIRO_HAS_PDF_SURFACE
46#ifdef CAIRO_HAS_PS_SURFACE
109#if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 16, 0) && CAIRO_VERSION < CAIRO_VERSION_ENCODE(1, 17, 0)
113struct CairoTagNumpunct : std::numpunct<char>
116 char do_decimal_point()
const override {
117 return *std::localeconv()->decimal_point;
124class CairoTagStringStream :
public std::ostringstream
127 CairoTagStringStream()
129 #if defined _CAIRO_1_16
130 imbue(std::locale(std::locale::classic(),
new CairoTagNumpunct));
132 imbue(std::locale::classic());
163 double const floor_size = std::floor(dims[axis]);
173class ContextPaintManager
176 ContextPaintManager(
SPStyle *target_style,
SPItem const *style_origin)
177 : _managed_style{target_style}
178 , _origin{style_origin}
180 auto const fill_origin = target_style->
fill.paintOrigin;
182 _copyPaint(&target_style->
fill, *_origin->style->getFillOrStroke(
true));
184 _copyPaint(&target_style->
fill, *_origin->style->getFillOrStroke(
false));
187 auto const stroke_origin = target_style->
stroke.paintOrigin;
189 _copyPaint(&target_style->
stroke, *_origin->style->getFillOrStroke(
true));
191 _copyPaint(&target_style->
stroke, *_origin->style->getFillOrStroke(
false));
195 ~ContextPaintManager()
199 _managed_style->fill = _old_fill;
201 if (_rewrote_stroke) {
202 _managed_style->stroke = _old_stroke;
208 template<
typename PainT>
209 void _copyPaint(PainT *destination,
SPIPaint paint)
212 if constexpr (std::is_same<PainT,
decltype(_old_fill)>::value) {
213 _rewrote_fill =
true;
214 _old_fill = *destination;
215 }
else if constexpr (std::is_same<PainT,
decltype(_old_stroke)>::value) {
216 _rewrote_stroke =
true;
217 _old_stroke = *destination;
219 static_assert(std::is_same_v<PainT,
decltype(_old_fill)> || std::is_same_v<PainT,
decltype(_old_stroke)>,
220 "ContextPaintManager::_copyPaint() instantiated with neither fill nor stroke type.");
222 new_value.upcast()->operator=(paint);
223 *destination = new_value;
228 decltype(_managed_style->
fill) _old_fill;
229 decltype(_managed_style->
stroke) _old_stroke;
230 bool _rewrote_fill =
false;
231 bool _rewrote_stroke =
false;
236 if (!shape->
curve()) {
247 std::unique_ptr<ContextPaintManager> context_fs_manager;
250 context_fs_manager = std::make_unique<ContextPaintManager>(style,
origin);
271 for (
auto const &[_, marker, tr] : shape->
get_markers()) {
273 auto const old_tr = marker_item->transform;
274 marker_item->transform = old_tr * marker->c2p * tr;
277 marker_item->transform = old_tr;
301 if (
auto item = cast<SPItem>(&obj)) {
309 bool translated =
false;
344 if (!
image->pixbuf) {
354 double const w =
static_cast<double>(
image->pixbuf->width());
355 double const h =
static_cast<double>(
image->pixbuf->height());
356 double x =
image->x.computed;
357 double y =
image->y.computed;
375 auto link = Glib::ustring::compose(
"uri='%1'", a->
href);
381 link = Glib::ustring::compose(
"dest='%1'", obj->getId());
386 CairoTagStringStream os;
390 os <<
" rect=[" << bbox.left() <<
" " << bbox.top() <<
" " << bbox.width() <<
" " << bbox.height() <<
"]";
397 for (
auto const &
object : a->
children) {
398 if (
auto item = cast<SPItem>(&
object)) {
420 double view_width, view_height;
434 vb2user[0] =
width / view_width;
435 vb2user[3] =
height / view_height;
436 vb2user[4] = x - symbol->
viewBox.
left() * vb2user[0];
437 vb2user[5] = y - symbol->
viewBox.
top() * vb2user[3];
450 root->height.computed);
475 TRACE((
"sp_asbitmap_render: resolution: %f\n", res ));
494 double scale_x = bbox->width() /
width;
495 double scale_y = bbox->height() /
height;
498 double shift_x = bbox->min()[
Geom::X];
499 double shift_y = bbox->top();
503 shift_x = round (shift_x);
504 shift_y = round (shift_y);
527 bool is_linked =
false;
529 is_linked |= is<SPAnchor>(link);
539 if (
auto root = cast<SPRoot>(
item)) {
542 }
else if (
auto symbol = cast<SPSymbol>(
item)) {
545 }
else if (
auto anchor = cast<SPAnchor>(
item)) {
548 }
else if (
auto shape = cast<SPShape>(
item)) {
551 }
else if (
auto use = cast<SPUse>(
item)) {
552 TRACE((
"use begin---\n"));
554 TRACE((
"---use end\n"));
555 }
else if (
auto text = cast<SPText>(
item)) {
558 }
else if (
auto flowtext = cast<SPFlowtext>(
item)) {
559 TRACE((
"flowtext\n"));
561 }
else if (
auto image = cast<SPImage>(
item)) {
564 }
else if (is<SPMarker>(
item)) {
566 }
else if (
auto group = cast<SPGroup>(
item)) {
582 if (
auto const *clone = cast<SPUse>(
item)) {
583 return clone->anyInChain([](
SPItem const *i) {
return i && i->
isFiltered(); });
613 auto group = cast<SPGroup>(
item);
621 if (state->need_layer) {
647 if (!pathv.
empty()) {
665 double px_to_ctx_units = 1.0;
676 TRACE((
"setupDocument: %f x %f\n",
width,
height));
687 if (pages.size() == 0) {
693 for (
auto &
page : pages) {
703 g_warning(
"Couldn't render page in output!");
718 auto const rect =
page->getBleed();
719 auto const exact_rect = rect *
scale * unit_conversion;
722 if (stretch_to_fit) {
724 auto distortion =
Geom::Scale(final_width / exact_rect.width(),
725 final_height / exact_rect.height());
735 ctx->
nextPage(final_width, final_height,
page->label());
740 for (
auto &
child :
page->getOverlappingItems(
false,
true,
false)) {
744 for (
auto anc :
child->ancestorList(
true)) {
745 if (
auto layer = cast<SPItem>(anc)) {
763 g_assert( ctx !=
nullptr && ctx->
_is_valid );
776 t[4] = clip_bbox.
left();
777 t[5] = clip_bbox.
top();
783 TRACE((
"BEGIN clip\n"));
799 TRACE((
"END clip\n"));
804 cairo_clip(ctx->
_cr);
816 g_assert( ctx !=
nullptr && ctx->
_is_valid );
826 t[4] = mask_bbox.
left();
827 t[5] = mask_bbox.
top();
839 TRACE((
"BEGIN mask\n"));
845 TRACE((
"END mask\n"));
852 double *x,
double *y,
double *
width,
double *
height)
857 double scalex, scaley,
scale;
858 double new_width, new_height;
859 scalex = *
width / vp_width;
860 scaley = *
height / vp_height;
862 new_width = vp_width *
scale;
863 new_height = vp_height *
scale;
865 switch (aspect_align) {
869 *x -= 0.5 * (new_width - *
width);
872 *x -= 1.0 * (new_width - *
width);
875 *y -= 0.5 * (new_height - *
height);
878 *x -= 0.5 * (new_width - *
width);
879 *y -= 0.5 * (new_height - *
height);
882 *x -= 1.0 * (new_width - *
width);
883 *y -= 0.5 * (new_height - *
height);
886 *y -= 1.0 * (new_height - *
height);
889 *x -= 0.5 * (new_width - *
width);
890 *y -= 1.0 * (new_height - *
height);
893 *x -= 1.0 * (new_width - *
width);
894 *y -= 1.0 * (new_height - *
height);
Cartesian point / 2D vector and related operations.
Declaration of CairoRenderContext, a class used for rendering with Cairo.
Declaration of CairoRenderer, a class used for rendering via a CairoRenderContext.
cairo_operator_t ink_css_blend_to_cairo_operator(SPBlendMode css_blend)
Cairo integration helpers.
3x3 matrix representing an affine transformation.
Affine inverse() const
Compute the inverse matrix.
static CRect from_xywh(Coord x, Coord y, Coord w, Coord h)
Create rectangle from origin and dimensions.
C top() const
Return top coordinate of the rectangle (+Y is downwards).
C left() const
Return leftmost coordinate of the rectangle (+X is to the right).
C height() const
Get the vertical extent of the rectangle.
C width() const
Get the horizontal extent of the rectangle.
CPoint dimensions() const
Get rectangle's width and height as a point.
Axis-aligned rectangle that can be empty.
bool empty() const
Check whether the vector contains any paths.
Two-dimensional point that doubles as a vector.
Axis aligned, non-empty rectangle.
Translate inverse() const
Get the inverse translation.
CairoRenderMode getRenderMode() const
CairoClipMode getClipMode() const
unsigned getBitmapResolution()
void setTransform(Geom::Affine const &transform)
void setMetadata(SPDocument const &document)
Extract metadata from the document and store it in the context.
CairoRenderer * getRenderer() const
bool renderPathVector(Geom::PathVector const &pathv, SPStyle const *style, Geom::OptRect const &pbox, CairoPaintOrder order=STROKE_OVER_FILL)
void setStateForItem(SPItem const *item)
Geom::Affine getTransform() const
bool renderImage(Inkscape::Pixbuf const *pb, Geom::Affine const &image_transform, SPStyle const *style)
void destBegin(const char *link)
const CairoRenderState * getCurrentState() const
bool nextPage(double width, double height, char const *label)
When writing multiple pages, resize the next page.
unsigned int _vector_based_target
void transform(Geom::Affine const &transform)
bool finishPage()
Each page that's made should call finishPage to complete it.
void tagBegin(const char *link)
void setStateMergeOpacity(bool state_merge_opacity)
void setRenderMode(CairoRenderMode mode)
void setStateForStyle(SPStyle const *style)
bool setupSurface(double width, double height)
Creates the cairo_surface_t for the context with the given width, height and with the currently set t...
void addClippingRect(double x, double y, double width, double height)
void setStateNeedsLayer(bool state_needs_layer)
void popLayer(cairo_operator_t composite=CAIRO_OPERATOR_CLEAR)
bool renderPage(CairoRenderContext *ctx, SPDocument *doc, SPPage const *page, bool stretch_to_fit)
void renderItem(CairoRenderContext *ctx, SPItem const *item, SPItem const *origin=nullptr, SPPage const *page=nullptr)
Traverses the object tree and invokes the render methods.
void applyMask(CairoRenderContext *ctx, SPMask const *mask)
bool renderPages(CairoRenderContext *ctx, SPDocument *doc, bool stretch_to_fit)
Handle multiple pages, pushing each out to cairo as needed using renderItem()
void renderHatchPath(CairoRenderContext *ctx, SPHatchPath const &hatchPath, unsigned key)
CairoRenderContext createContext()
void applyClipPath(CairoRenderContext *ctx, SPClipPath const *cp)
static bool _shouldRasterize(CairoRenderContext *ctx, SPItem const *item)
Decide whether the given item should be rendered as a bitmap.
bool setupDocument(CairoRenderContext *ctx, SPDocument *doc, SPItem const *base=nullptr)
Initializes the CairoRenderContext according to the specified SPDocument.
static void _doRender(SPItem const *item, CairoRenderContext *ctx, SPItem const *origin=nullptr, SPPage const *page=nullptr)
Render a single item in a fully set up context.
const std::vector< SPPage * > & getPages() const
void showGlyphs(CairoRenderContext *ctx) const
Renders all the glyphs to the given Cairo rendering context.
static double convert(double from_dist, Unit const *from, Unit const *to)
Convert distances.
std::unique_ptr< Inkscape::URIReference > local_link
Geom::OptRect get_last_bbox() const
bool clippath_units() const
Geom::PathVector const & get_pathvector() const
Typed SVG document implementation.
SPRoot * getRoot()
Returns our SPRoot.
Geom::Point getDimensions() const
Geom::OptRect preferredBounds() const
Inkscape::PageManager & getPageManager()
Geom::Scale getDocumentScale(bool computed=true) const
Returns document scale as defined by width/height (in pixels) and viewBox (real world to user-units).
Inkscape::Text::Layout layout
SPCurve calculateRenderCurve(unsigned key) const
Paint type internal to SPStyle.
Base class for visual SVG elements.
Geom::OptRect documentVisualBounds() const
Get item's visual bbox in document coordinate system.
SPObject * isInClipPath() const
Geom::OptRect geometricBounds(Geom::Affine const &transform=Geom::identity()) const
Get item's geometric bounding box in this item's coordinate system.
Geom::Affine i2doc_affine() const
Returns the accumulated transformation of the item and all its ancestors, including root's viewport.
bool isFiltered() const
Returns true if the item is filtered, false otherwise.
Geom::OptRect visualBounds(Geom::Affine const &transform=Geom::identity(), bool wfilter=true, bool wclip=true, bool wmask=true) const
Get item's visual bounding box in this item's coordinate system.
Geom::OptRect get_last_bbox() const
bool mask_content_units() const
SPObject is an abstract base class of all of the document nodes at the SVG document level.
char const * getId() const
Returns the objects current ID string.
SPStyle * style
Represents the style properties, whether from presentation attributes, the style attribute,...
virtual void getLinked(std::vector< SPObject * > &objects, LinkedObjectNature direction=LinkedObjectNature::ANY) const
Get objects which are linked to this object as either a source or a target.
Base class for shapes, including <path> element.
SPCurve const * curve() const
Return a borrowed pointer to the curve (if any exists) or NULL if there is no curve.
std::vector< std::tuple< SPMarkerLoc, SPMarker *, Geom::Affine > > get_markers() const
Lists every marker on this shape along with its transform and marker type.
T< SPAttr::FILL, SPIPaint > fill
fill
T< SPAttr::STROKE, SPIPaint > stroke
stroke
T< SPAttr::PAINT_ORDER, SPIPaintOrder > paint_order
T< SPAttr::STROKE_WIDTH, SPILength > stroke_width
stroke-width
T< SPAttr::MIX_BLEND_MODE, SPIEnum< SPBlendMode > > mix_blend_mode
Inkscape::Text::Layout layout
unsigned int aspect_align
A way to clear the N_ macro, which is defined as an inline function.
@ SP_CONTENT_UNITS_OBJECTBOUNDINGBOX
static bool has_stroke(SPObject *source)
bool has_hidder_filter(SPObject const *item)
constexpr Coord EPSILON
Default "acceptably small" value.
std::unique_ptr< Magick::Image > image
Affine identity()
Create an identity matrix.
static void sp_use_render(SPUse const *use, CairoRenderContext *ctx, SPPage const *page=nullptr)
static void sp_group_render(SPGroup const *group, CairoRenderContext *ctx, SPItem const *origin=nullptr, SPPage const *page=nullptr)
static void sp_flowtext_render(SPFlowtext const *flowtext, CairoRenderContext *ctx)
static void sp_symbol_render(SPSymbol const *symbol, CairoRenderContext *ctx, SPItem const *origin, SPPage const *page)
void calculatePreserveAspectRatio(unsigned int aspect_align, unsigned int aspect_clip, double vp_width, double vp_height, double *x, double *y, double *width, double *height)
static void sp_anchor_render(SPAnchor const *a, CairoRenderContext *ctx, SPItem const *origin, SPPage const *page)
static void sp_shape_render(SPShape const *shape, CairoRenderContext *ctx, SPItem const *origin=nullptr)
static void sp_root_render(SPRoot const *root, CairoRenderContext *ctx)
static void sp_item_invoke_render(SPItem const *item, CairoRenderContext *ctx, SPItem const *origin=nullptr, SPPage const *page=nullptr)
static void sp_image_render(SPImage const *image, CairoRenderContext *ctx)
static Geom::Point compute_final_page_dimensions(Geom::Rect const &page_rect)
Compute the final page dimensions in the resulting PS or PDF.
static void sp_text_render(SPText const *text, CairoRenderContext *ctx)
static void sp_asbitmap_render(SPItem const *item, CairoRenderContext *ctx, SPPage const *page=nullptr)
This function converts the item to a raster image and includes the image into the cairo renderer.
Helper class to stream background task notifications as a series of messages.
static cairo_user_data_key_t key
PathVector - a sequence of subpaths.
Inkscape::Pixbuf * sp_generate_internal_bitmap(SPDocument *document, Geom::Rect const &area, double dpi, std::vector< SPItem const * > items, bool opaque, uint32_t const *checkerboard_color, double device_scale, std::optional< Antialiasing > antialias)
Generates a bitmap from given items.
TODO: insert short description here.
SVG <hatchPath> implementation.
SVG <image> implementation.
SPItem const * sp_item_first_item_child(SPObject const *obj)
Some things pertinent to all visible shapes: SPItem, SPItemView, SPItemCtx.
TODO: insert short description here.
TODO: insert short description here.
SPRoot: SVG <svg> implementation.
unsigned need_layer
whether object is masked, clipped, and/or has a non-zero opacity
Geom::Affine item_transform
this item's item->transform, for correct clipping
SPStyle internal: classes that are internal to SPStyle.
@ SP_CSS_PAINT_ORIGIN_CONTEXT_STROKE
@ SP_CSS_PAINT_ORIGIN_CONTEXT_FILL
@ SP_CSS_PAINT_ORDER_STROKE
@ SP_CSS_PAINT_ORDER_MARKER
@ SP_CSS_PAINT_ORDER_FILL
@ SP_CSS_PAINT_ORDER_NORMAL