Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 27 additions & 22 deletions engine/cairoShimCairo.cc
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#endif

using namespace std;
using ecolab::Pango;

namespace minsky
{
Expand Down Expand Up @@ -98,17 +99,33 @@ namespace minsky
{cairo_set_source_rgba(cairo,r,g,b,a);}

// Text operations
void CairoShimCairo::showText(const std::string& text) const
{cairo_show_text(cairo,text.c_str());}

void CairoShimCairo::setFontSize(double size) const
{cairo_set_font_size(cairo, size);}

void CairoShimCairo::selectFontFace(const std::string& family, cairo_font_slant_t slant, cairo_font_weight_t weight) const
{cairo_select_font_face(cairo, family.c_str(), slant, weight);}
void CairoShimCairo::initPango(Pango& pango,const TextProperties& tp) const
{
if (!tp.markup.empty())
pango.setMarkup(tp.markup);
else if (!tp.plainText.empty())
pango.setText(tp.plainText);
pango.angle=tp.angle;
if (isfinite(tp.fontSize))
pango.setFontSize(tp.fontSize);
if (!tp.fontFamily.empty())
pango.setFontFamily(tp.fontFamily.c_str());
}

void CairoShimCairo::showText(const TextProperties& tp) const
{
if (tp.markup.empty() && tp.plainText.empty()) return;
Pango pango(cairo);
initPango(pango,tp);
pango.show();
}

void CairoShimCairo::textExtents(const std::string& text, cairo_text_extents_t& extents) const
{cairo_text_extents(cairo,text.c_str(),&extents);}
TextExtents CairoShimCairo::textExtents(const TextProperties& tp) const
{
Pango pango(cairo);
initPango(pango,tp);
return {pango.left(), pango.top(), pango.width(), pango.height()};
}

// Transformation operations
void CairoShimCairo::identityMatrix() const
Expand Down Expand Up @@ -137,18 +154,6 @@ namespace minsky
void CairoShimCairo::setTolerance(double tolerance) const
{cairo_set_tolerance(cairo, tolerance);}

// Pango support
ecolab::Pango& CairoShimCairo::pango() const
{
if (!m_pango) newPango();
return *m_pango;
}
ecolab::Pango& CairoShimCairo::newPango() const
{
m_pango.reset(new ecolab::Pango(cairo));
return *m_pango;
}

// SVG rendering support
void CairoShimCairo::renderSVG(const SVGRenderer& svgRenderer, double width, double height) const
{
Expand Down
14 changes: 5 additions & 9 deletions engine/cairoShimCairo.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ namespace minsky
class CairoShimCairo: public ICairoShim
{
cairo_t* cairo;
mutable std::unique_ptr<ecolab::Pango> m_pango;
void initPango(ecolab::Pango&,const TextProperties&) const;
CairoShimCairo(const CairoShimCairo&)=delete;
void operator=(const CairoShimCairo&)=delete;
public:
Expand Down Expand Up @@ -56,10 +56,8 @@ namespace minsky
void setSourceRGBA(double r, double g, double b, double a) const override;

// Text operations
void showText(const std::string& text) const override;
void setFontSize(double size) const override;
void selectFontFace(const std::string& family, cairo_font_slant_t slant, cairo_font_weight_t weight) const override;
void textExtents(const std::string& text, cairo_text_extents_t& extents) const override;
void showText(const TextProperties& text) const override;
TextExtents textExtents(const TextProperties& text) const override;

// Transformation operations
void identityMatrix() const override;
Expand All @@ -75,15 +73,13 @@ namespace minsky
// Tolerance
void setTolerance(double tolerance) const override;

// Pango support
ecolab::Pango& pango() const override;
ecolab::Pango& newPango() const override;

// SVG rendering support
void renderSVG(const SVGRenderer& svgRenderer, double width, double height) const override;

// TEMPORARY: Internal accessor for migration - to be removed once all implementations are updated
cairo_t* _internalGetCairoContext() const { return cairo; }

void* context() const override {return cairo;}
};

}
Expand Down
131 changes: 101 additions & 30 deletions model/ICairoShim.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,91 +20,162 @@
#ifndef ICAIROSHIM_H
#define ICAIROSHIM_H

#include <cmath>
#include <memory>
#include <string>
#include <cairo.h>

// Forward declarations
namespace ecolab { class Pango; }

namespace minsky
{
class SVGRenderer;

struct TextProperties
{
// markup overrides the text entry
std::string markup, plainText;
double fontSize=std::nan("");
double angle=0;
std::string fontFamily;
TextProperties(const std::string& markup="", const std::string& plainText="", double fontSize=std::nan("")):
markup(markup), plainText(plainText), fontSize(fontSize) {}
TextProperties(const std::string& markup, double fontSize):
markup(markup), fontSize(fontSize) {}
};

struct TextExtents
{
double left, top, width, height;
};

/// cache results of font rendering to amortise setup costs
class ICacheRender
{
public:
virtual ~ICacheRender()=default;
virtual void show()=0;
virtual TextExtents extents() const=0;
virtual void* context() const=0;
};

class ICairoShim;

/// a simple minded implementation that doesn't cache
class NonCachedRenderer: public ICacheRender
{
TextProperties text;
const ICairoShim& shim;
public:
NonCachedRenderer(const TextProperties& text, const ICairoShim& shim):
text(text), shim(shim) {}
void show() override;
TextExtents extents() const override;
void* context() const override;
};

/// Abstract interface for Cairo drawing operations
class ICairoShim
{
public:
virtual ~ICairoShim() = default;

// Drawing operations
/// @{ Drawing operations
virtual void moveTo(double x, double y) const = 0;
virtual void lineTo(double x, double y) const = 0;
virtual void relMoveTo(double x, double y) const = 0;
virtual void relLineTo(double x, double y) const = 0;
virtual void arc(double x, double y, double radius, double start, double end) const = 0;
virtual void curveTo(double x1, double y1, double x2, double y2, double x3, double y3) const = 0;
virtual void rectangle(double x, double y, double width, double height) const = 0;

// Path operations
/// @}

/// @{ Path operations
virtual void newPath() const = 0;
virtual void newSubPath() const = 0;
virtual void closePath() const = 0;
virtual void getCurrentPoint(double& x, double& y) const = 0;

// Fill and stroke operations
/// @}

/// @{ Fill and stroke operations
virtual void fill() const = 0;
virtual void fillPreserve() const = 0;
virtual void stroke() const = 0;
virtual void strokePreserve() const = 0;
virtual void clip() const = 0;
virtual void resetClip() const = 0;
virtual void paint() const = 0;

// Line properties
/// @}

/// @{ Line properties
virtual void setLineWidth(double width) const = 0;
virtual double getLineWidth() const = 0;
virtual void setDash(const double* dashes, int num_dashes, double offset) const = 0;
virtual void setFillRule(cairo_fill_rule_t fill_rule) const = 0;

// Color operations
/// @}

/// @{ Color operations
virtual void setSourceRGB(double r, double g, double b) const = 0;
virtual void setSourceRGBA(double r, double g, double b, double a) const = 0;

// Text operations
virtual void showText(const std::string& text) const = 0;
virtual void setFontSize(double size) const = 0;
virtual void selectFontFace(const std::string& family, cairo_font_slant_t slant, cairo_font_weight_t weight) const = 0;
virtual void textExtents(const std::string& text, cairo_text_extents_t& extents) const = 0;

// Transformation operations
/// @}

/// render text
virtual void showText(const TextProperties& text) const = 0;
/// show markup text
void showText(const std::string& s, double fs=std::nan("")) const
{showText(TextProperties(s,fs));}
/// show text with no markup interpretation
void showPlainText(const std::string& s, double fs=std::nan("")) const
{showText(TextProperties("",s,fs));}
// virtual void setFontSize(double size) const = 0;
// virtual void selectFontFace(const std::string& family, cairo_font_slant_t slant, cairo_font_weight_t weight) const = 0;
/// return metrics for a given bit of text
virtual TextExtents textExtents(const TextProperties& text) const = 0;

/// @{ Transformation operations
virtual void identityMatrix() const = 0;
virtual void translate(double x, double y) const = 0;
virtual void scale(double sx, double sy) const = 0;
virtual void rotate(double angle) const = 0;
virtual void userToDevice(double& x, double& y) const = 0;

// Context state operations
/// @}

/// @{ Context state operations
virtual void save() const = 0;
virtual void restore() const = 0;

// Tolerance
/// @}

/// Tolerance
virtual void setTolerance(double tolerance) const = 0;

// TODO: this needs to be fixed with a proper text rendering interface.
// For now use a newPango call that resets the pango
// Pango support for text rendering
virtual ecolab::Pango& pango() const = 0;
virtual ecolab::Pango& newPango() const = 0;

// SVG rendering support
/// Render an SVG resource into a region of size width x height
/// @param svgRenderer - Reference to SVGRenderer containing the loaded SVG resource
/// @param width - target width for rendering
/// @param height - target height for rendering
virtual void renderSVG(const SVGRenderer& svgRenderer, double width, double height) const = 0;

/// returns reference to underlying context for caching purposes
virtual void* context() const=0;

/// return a cached object of rendered text
virtual std::unique_ptr<ICacheRender> cachedRender(const TextProperties& tp) const
{return std::make_unique<NonCachedRenderer>(tp,*this);}
};

/// RAII wrapper around save/restore
struct CairoShimSave
{
const ICairoShim& shim;
CairoShimSave(const ICairoShim& shim): shim(shim) {shim.save();}
~CairoShimSave() {shim.restore();}
};

inline void NonCachedRenderer::show()
{shim.showText(text);}
inline TextExtents NonCachedRenderer::extents() const
{return shim.textExtents(text);}
inline void* NonCachedRenderer::context() const
{return shim.context();}

}

#include "ICairoShim.xcd"
Expand Down
42 changes: 23 additions & 19 deletions model/cairoItems.cc
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
#include "minsky.h"

#include "cairoItems.h"
#include "../engine/cairoShimCairo.h"
#include "cairoShimCairo.h"
#include "operation.h"
#include "latexMarkup.h"
#include <arrays.h>
Expand All @@ -46,47 +46,51 @@ using namespace boost::geometry;

namespace
{
// for use when calculating bounding boxes, but not drawing to anything?
cairo::Surface dummySurf(cairo_image_surface_create(CAIRO_FORMAT_A1, 100,100));
CairoShimCairo dummyCairoShim(dummySurf.cairo());
}

RenderVariable::RenderVariable(const VariableBase& var, cairo_t* cairo):
Pango(cairo? cairo: dummySurf.cairo()), var(var), cairo(cairo)
RenderVariable::RenderVariable(const VariableBase& var, const ICairoShim& shim):
var(var), cairoShim(shim), m_context(cairoShim.context())
{
setFontSize(12);
TextProperties textProperties;
textProperties.fontSize=12;
if (var.type()==VariableType::constant)
{
try
{
auto val=var.engExp();
if (val.engExp==-3) val.engExp=0; //0.001-1.0
setMarkup(var.mantissa(val)+expMultiplier(val.engExp));
textProperties.markup=var.mantissa(val)+expMultiplier(val.engExp);
}
catch (const std::exception& ex)
{
setMarkup("0");
textProperties.markup="0";
}
w=0.5*Pango::width();
h=0.5*Pango::height();
auto bbox=shim.textExtents(textProperties);
w=0.5*bbox.width;
h=0.5*bbox.height;
hoffs=bbox.top;
}
else
{
setMarkup(latexToPango(var.name()));
w=0.5*Pango::width();
h=0.5*Pango::height();
textProperties.markup=latexToPango(var.name());
auto bbox=shim.textExtents(textProperties);
w=0.5*bbox.width;
h=0.5*bbox.height;
if (!var.ioVar())
{ // add additional space for numerical display
w+=12;
{ // add additional space for numerical display
w+=12;
h+=4;
}
hoffs=bbox.top;
}
hoffs=Pango::top();
cachedRenderer=cairoShim.cachedRender(textProperties);
}

void RenderVariable::draw()
{
CairoShimCairo shim(cairo);
var.draw(shim);
}
RenderVariable::RenderVariable(const VariableBase& var):
RenderVariable(var, dummyCairoShim) {}

bool RenderVariable::inImage(float x, float y)
{
Expand Down
Loading
Loading