Skip to content

Commit

Permalink
fix pixel aligned drawing
Browse files Browse the repository at this point in the history
  • Loading branch information
scheffle committed Oct 11, 2020
1 parent 1b07b8f commit b065e1b
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 37 deletions.
36 changes: 19 additions & 17 deletions vstgui/lib/platform/linux/cairocontext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ struct SaveCairoState
{
SaveCairoState (ContextHandle& h) : h (h) { cairo_save (h); }
~SaveCairoState () { cairo_restore (h); }

private:
ContextHandle& h;
};
Expand Down Expand Up @@ -71,9 +72,9 @@ DrawBlock::DrawBlock (Context& context) : context (context)
cairo_clip (context.getCairo ());
auto matrix = convert (ct);
cairo_set_matrix (context.getCairo (), &matrix);
auto antialiasMode = context.getDrawMode ().modeIgnoringIntegralMode () == kAntiAliasing ?
CAIRO_ANTIALIAS_BEST :
CAIRO_ANTIALIAS_NONE;
auto antialiasMode = context.getDrawMode ().modeIgnoringIntegralMode () == kAntiAliasing
? CAIRO_ANTIALIAS_BEST
: CAIRO_ANTIALIAS_NONE;
cairo_set_antialias (context.getCairo (), antialiasMode);
}
}
Expand Down Expand Up @@ -113,9 +114,7 @@ Context::Context (CRect r, cairo_t* context) : super (r)
}

//-----------------------------------------------------------------------------
Context::~Context ()
{
}
Context::~Context () {}

//-----------------------------------------------------------------------------
void Context::init ()
Expand Down Expand Up @@ -161,7 +160,7 @@ void Context::setSourceColor (CColor color)
auto alpha = color.normAlpha<double> ();
alpha *= getGlobalAlpha ();
cairo_set_source_rgba (cr, color.normRed<double> (), color.normGreen<double> (),
color.normBlue<double> (), alpha);
color.normBlue<double> (), alpha);
checkCairoStatus (cr);
}

Expand Down Expand Up @@ -263,8 +262,8 @@ void Context::drawLine (const CDrawContext::LinePair& line)
{
CPoint start = pixelAlign (getCurrentTransform (), line.first);
CPoint end = pixelAlign (getCurrentTransform (), line.second);
cairo_move_to (cr, start.x + 0.5, start.y + 0.5);
cairo_line_to (cr, end.x + 0.5, end.y + 0.5);
cairo_move_to (cr, start.x, start.y);
cairo_line_to (cr, end.x, end.y);
}
else
{
Expand All @@ -289,8 +288,8 @@ void Context::drawLines (const CDrawContext::LineList& lines)
{
CPoint start = pixelAlign (getCurrentTransform (), line.first);
CPoint end = pixelAlign (getCurrentTransform (), line.second);
cairo_move_to (cr, start.x + 0.5, start.y + 0.5);
cairo_line_to (cr, end.x + 0.5, end.y + 0.5);
cairo_move_to (cr, start.x, start.y);
cairo_line_to (cr, end.x, end.y);
cairo_stroke (cr);
}
}
Expand Down Expand Up @@ -333,7 +332,7 @@ void Context::drawRect (const CRect& rect, const CDrawStyle drawStyle)
if (needPixelAlignment (getDrawMode ()))
{
r = pixelAlign (getCurrentTransform (), r);
cairo_rectangle (cr, r.left + 0.5, r.top + 0.5, r.getWidth (), r.getHeight ());
cairo_rectangle (cr, r.left, r.top, r.getWidth (), r.getHeight ());
}
else
cairo_rectangle (cr, r.left + 0.5, r.top + 0.5, r.getWidth () - 0.5,
Expand Down Expand Up @@ -386,27 +385,30 @@ void Context::drawBitmap (CBitmap* bitmap, const CRect& dest, const CPoint& offs
{
if (auto cd = DrawBlock::begin (*this))
{
double transformedScaleFactor = getScaleFactor();
double transformedScaleFactor = getScaleFactor ();
CGraphicsTransform t = getCurrentTransform ();
if (t.m11 == t.m22 && t.m12 == 0 && t.m21 == 0)
transformedScaleFactor *= t.m11;
auto cairoBitmap = bitmap->getBestPlatformBitmapForScaleFactor (transformedScaleFactor).cast<Bitmap> ();
auto cairoBitmap =
bitmap->getBestPlatformBitmapForScaleFactor (transformedScaleFactor).cast<Bitmap> ();
if (cairoBitmap)
{
cairo_translate (cr, dest.left, dest.top);
cairo_rectangle (cr, 0, 0, dest.getWidth (), dest.getHeight ());
cairo_clip (cr);

// Setup a pattern for scaling bitmaps and take it as source afterwards.
auto pattern = cairo_pattern_create_for_surface (cairoBitmap->getSurface());
auto pattern = cairo_pattern_create_for_surface (cairoBitmap->getSurface ());
cairo_matrix_t matrix;
cairo_pattern_get_matrix (pattern, &matrix);
cairo_matrix_init_scale (&matrix, cairoBitmap->getScaleFactor (), cairoBitmap->getScaleFactor ());
cairo_matrix_init_scale (&matrix, cairoBitmap->getScaleFactor (),
cairoBitmap->getScaleFactor ());
cairo_matrix_translate (&matrix, offset.x, offset.y);
cairo_pattern_set_matrix (pattern, &matrix);
cairo_set_source (cr, pattern);

cairo_rectangle (cr, -offset.x, -offset.y, dest.getWidth () + offset.x, dest.getHeight () + offset.y);
cairo_rectangle (cr, -offset.x, -offset.y, dest.getWidth () + offset.x,
dest.getHeight () + offset.y);
alpha *= getGlobalAlpha ();
if (alpha != 1.f)
{
Expand Down
37 changes: 26 additions & 11 deletions vstgui/lib/platform/linux/cairocontext.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// This file is part of VSTGUI. It is subject to the license terms
// This file is part of VSTGUI. It is subject to the license terms
// in the LICENSE file found in the top-level directory of this
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE

Expand Down Expand Up @@ -35,22 +35,22 @@ class Context : public COffscreenContext
void drawPolygon (const PointList& polygonPointList, const CDrawStyle drawStyle) override;
void drawRect (const CRect& rect, const CDrawStyle drawStyle) override;
void drawArc (const CRect& rect, const float startAngle1, const float endAngle2,
const CDrawStyle drawStyle) override;
const CDrawStyle drawStyle) override;
void drawEllipse (const CRect& rect, const CDrawStyle drawStyle) override;
void drawPoint (const CPoint& point, const CColor& color) override;
void drawBitmap (CBitmap* bitmap, const CRect& dest, const CPoint& offset,
float alpha) override;
float alpha) override;
void clearRect (const CRect& rect) override;
CGraphicsPath* createGraphicsPath () override;
CGraphicsPath* createTextPath (const CFontRef font, UTF8StringPtr text) override;
void drawGraphicsPath (CGraphicsPath* path, PathDrawMode mode,
CGraphicsTransform* transformation) override;
CGraphicsTransform* transformation) override;
void fillLinearGradient (CGraphicsPath* path, const CGradient& gradient,
const CPoint& startPoint, const CPoint& endPoint, bool evenOdd,
CGraphicsTransform* transformation) override;
const CPoint& startPoint, const CPoint& endPoint, bool evenOdd,
CGraphicsTransform* transformation) override;
void fillRadialGradient (CGraphicsPath* path, const CGradient& gradient, const CPoint& center,
CCoord radius, const CPoint& originOffset, bool evenOdd,
CGraphicsTransform* transformation) override;
CCoord radius, const CPoint& originOffset, bool evenOdd,
CGraphicsTransform* transformation) override;

void saveGlobalState () override;
void restoreGlobalState () override;
Expand All @@ -75,18 +75,33 @@ struct DrawBlock

~DrawBlock ();
operator bool () { return !clipIsEmpty; }

private:
explicit DrawBlock (Context& context);
Context& context;
bool clipIsEmpty {false};
};

//-----------------------------------------------------------------------------
template <typename T>
inline T pixelAlign (const CGraphicsTransform& tm, T obj)
inline CPoint pixelAlign (const CGraphicsTransform& tm, const CPoint& p)
{
auto obj = p;
tm.transform (obj);
obj.x = std::round (obj.x) - 0.5;
obj.y = std::round (obj.y) - 0.5;
tm.inverse ().transform (obj);
return obj;
}

//-----------------------------------------------------------------------------
inline CRect pixelAlign (const CGraphicsTransform& tm, const CRect& r)
{
auto obj = r;
tm.transform (obj);
obj.makeIntegral ();
obj.left = std::round (obj.left) - 0.5;
obj.right = std::round (obj.right) - 0.5;
obj.top = std::round (obj.top) - 0.5;
obj.bottom = std::round (obj.bottom) - 0.5;
tm.inverse ().transform (obj);
return obj;
}
Expand Down
16 changes: 7 additions & 9 deletions vstgui/lib/platform/linux/cairopath.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// This file is part of VSTGUI. It is subject to the license terms
// This file is part of VSTGUI. It is subject to the license terms
// in the LICENSE file found in the top-level directory of this
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE

Expand All @@ -12,9 +12,7 @@ namespace VSTGUI {
namespace Cairo {

//------------------------------------------------------------------------
Path::Path (const ContextHandle& cr) noexcept : cr (cr)
{
}
Path::Path (const ContextHandle& cr) noexcept : cr (cr) {}

//------------------------------------------------------------------------
Path::~Path () noexcept
Expand Down Expand Up @@ -101,7 +99,7 @@ cairo_path_t* Path::getPath (const ContextHandle& handle, const CGraphicsTransfo
{
auto p = pixelAlign (*alignTm,
CPoint {e.instruction.point.x, e.instruction.point.y});
cairo_move_to (handle, p.x - 0.5, p.y - 0.5);
cairo_move_to (handle, p.x, p.y);
}
else
cairo_move_to (handle, e.instruction.point.x, e.instruction.point.y);
Expand All @@ -118,7 +116,7 @@ cairo_path_t* Path::getPath (const ContextHandle& handle, const CGraphicsTransfo
{
auto p = pixelAlign (*alignTm,
CPoint {e.instruction.point.x, e.instruction.point.y});
cairo_line_to (handle, p.x - 0.5, p.y - 0.5);
cairo_line_to (handle, p.x, p.y);
}
else
cairo_line_to (handle, e.instruction.point.x, e.instruction.point.y);
Expand All @@ -139,8 +137,7 @@ cairo_path_t* Path::getPath (const ContextHandle& handle, const CGraphicsTransfo
auto r = pixelAlign (
*alignTm, CRect {e.instruction.rect.left, e.instruction.rect.top,
e.instruction.rect.right, e.instruction.rect.bottom});
cairo_rectangle (handle, r.left - 0.5, r.top - 0.5, r.getWidth (),
r.getHeight ());
cairo_rectangle (handle, r.left, r.top, r.getWidth (), r.getHeight ());
}
else
{
Expand All @@ -150,7 +147,8 @@ cairo_path_t* Path::getPath (const ContextHandle& handle, const CGraphicsTransfo
}
break;
}
case Element::Type::kEllipse: {
case Element::Type::kEllipse:
{
#warning TODO: Implementation Element::Type::kEllipse
break;
}
Expand Down

0 comments on commit b065e1b

Please sign in to comment.