Skip to content

Commit

Permalink
Correct device_to_user and user_to_device implementation for Quartz2D
Browse files Browse the repository at this point in the history
  • Loading branch information
djowel committed Dec 15, 2023
1 parent 18e520b commit b227ad4
Showing 1 changed file with 40 additions and 10 deletions.
50 changes: 40 additions & 10 deletions lib/impl/macos/quartz2d/canvas.mm
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,11 @@
float scale() const { return _scale; }
void scale(float sc) { _scale = sc; }

using cg_affine = CGAffineTransform;

void get_inv_affine(CGContextRef context);
cg_affine const& get_inv_affine() const;

private:

struct state_info
Expand All @@ -79,11 +84,12 @@
state_info_stack _stack;
fill_rule_enum _fill_rule = fill_rule_enum::fill_winding;
float _scale;
CGAffineTransform _inv_affine;
};

#pragma clang diagnostic ignored "-Wvla-extension"

namespace
namespace
{
void make_gradient(std::vector<canvas::color_stop> const& space, CGGradientRef& gradient)
{
Expand Down Expand Up @@ -196,6 +202,17 @@ void make_gradient(std::vector<canvas::color_stop> const& space, CGGradientRef&
_stack.pop();
}

void canvas::canvas_state::get_inv_affine(CGContextRef context)
{
_inv_affine = CGAffineTransformInvert(CGContextGetCTM(context));
}

CGAffineTransform const&
canvas::canvas_state::get_inv_affine() const
{
return _inv_affine;
}

canvas::canvas(canvas_impl* context_)
: _context{context_}
, _state{std::make_unique<canvas_state>()}
Expand All @@ -208,6 +225,8 @@ void make_gradient(std::vector<canvas::color_stop> const& space, CGGradientRef&
CGPoint user = {100, 100};
auto device = CGContextConvertPointToDeviceSpace(ctx, user);
_state->scale(device.x / user.x);

_state->get_inv_affine(ctx);
}

canvas::~canvas()
Expand Down Expand Up @@ -251,20 +270,30 @@ void make_gradient(std::vector<canvas::color_stop> const& space, CGGradientRef&

point canvas::device_to_user(point p)
{
auto scale = _state->scale();
auto up = CGContextConvertPointToUserSpace(
CGContextRef(_context), {p.x * scale, p.y * scale}
);
// Get the current transform
auto af = CGContextGetCTM(CGContextRef(_context));

// Undo the initial transform
auto xaf = CGAffineTransformConcat(af, _state->get_inv_affine());

// Map the point to the inverted `xaf` transform
auto up = CGPointApplyAffineTransform({p.x, p.y}, CGAffineTransformInvert(xaf));

return {float(up.x), float(up.y)};
}

point canvas::user_to_device(point p)
{
auto scale = _state->scale();
auto dp = CGContextConvertPointToDeviceSpace(
CGContextRef(_context), {p.x, p.y}
);
return {float(dp.x / scale), float(dp.y / scale)};
// Get the current transform
auto af = CGContextGetCTM(CGContextRef(_context));

// Undo the initial transform
auto xaf = CGAffineTransformConcat(af, _state->get_inv_affine());

// Map the point to the `xaf` transform
auto up = CGPointApplyAffineTransform({p.x, p.y}, xaf);

return {float(up.x), float(up.y)};
}

affine_transform canvas::transform() const
Expand Down Expand Up @@ -699,6 +728,7 @@ CTLineRef measure_text(
auto line = CTLineCreateWithAttributedString(attr_string);
width = CTLineGetTypographicBounds(line, &ascent, &descent, &leading);
CFRelease(attr_string);
CFRelease(font_attributes);
return line;
}

Expand Down

0 comments on commit b227ad4

Please sign in to comment.