diff options
Diffstat (limited to 'src/platform/graphics/cairo/CairoPainter.cpp')
-rw-r--r-- | src/platform/graphics/cairo/CairoPainter.cpp | 183 |
1 files changed, 183 insertions, 0 deletions
diff --git a/src/platform/graphics/cairo/CairoPainter.cpp b/src/platform/graphics/cairo/CairoPainter.cpp index dcee70ad..1d457b8f 100644 --- a/src/platform/graphics/cairo/CairoPainter.cpp +++ b/src/platform/graphics/cairo/CairoPainter.cpp @@ -1,7 +1,14 @@ #include "cru/platform/graphics/cairo/CairoPainter.h" +#include "cru/common/Exception.h" +#include "cru/platform/Check.h" #include "cru/platform/Exception.h" #include "cru/platform/graphics/cairo/Base.h" +#include "cru/platform/graphics/cairo/CairoBrush.h" +#include "cru/platform/graphics/cairo/CairoGeometry.h" #include "cru/platform/graphics/cairo/CairoResource.h" +#include "cru/platform/graphics/cairo/PangoTextLayout.h" + +#include <pango/pangocairo.h> namespace cru::platform::graphics::cairo { CairoPainter::CairoPainter(CairoGraphicsFactory* factory, cairo_t* cairo, @@ -40,6 +47,182 @@ void CairoPainter::Clear(const Color& color) { cairo_paint(cairo_); } +void CairoPainter::DrawLine(const Point& start, const Point& end, IBrush* brush, + float width) { + CheckValidation(); + auto cairo_brush = CheckPlatform<CairoBrush>(brush, GetPlatformId()); + auto cairo_pattern = cairo_brush->GetCairoPattern(); + cairo_save(cairo_); + cairo_set_source(cairo_, cairo_pattern); + cairo_set_line_width(cairo_, width); + cairo_new_path(cairo_); + cairo_move_to(cairo_, start.x, start.y); + cairo_line_to(cairo_, end.x, end.y); + cairo_stroke(cairo_); + cairo_restore(cairo_); +} + +void CairoPainter::StrokeRectangle(const Rect& rectangle, IBrush* brush, + float width) { + CheckValidation(); + auto cairo_brush = CheckPlatform<CairoBrush>(brush, GetPlatformId()); + auto cairo_pattern = cairo_brush->GetCairoPattern(); + cairo_save(cairo_); + cairo_set_source(cairo_, cairo_pattern); + cairo_set_line_width(cairo_, width); + cairo_new_path(cairo_); + cairo_rectangle(cairo_, rectangle.left, rectangle.top, rectangle.width, + rectangle.height); + cairo_stroke(cairo_); + cairo_restore(cairo_); +} + +void CairoPainter::FillRectangle(const Rect& rectangle, IBrush* brush) { + CheckValidation(); + auto cairo_brush = CheckPlatform<CairoBrush>(brush, GetPlatformId()); + auto cairo_pattern = cairo_brush->GetCairoPattern(); + cairo_save(cairo_); + cairo_set_source(cairo_, cairo_pattern); + cairo_new_path(cairo_); + cairo_rectangle(cairo_, rectangle.left, rectangle.top, rectangle.width, + rectangle.height); + cairo_fill(cairo_); + cairo_restore(cairo_); +} + +void CairoPainter::StrokeEllipse(const Rect& outline_rect, IBrush* brush, + float width) { + CheckValidation(); + auto cairo_brush = CheckPlatform<CairoBrush>(brush, GetPlatformId()); + auto cairo_pattern = cairo_brush->GetCairoPattern(); + cairo_save(cairo_); + cairo_set_source(cairo_, cairo_pattern); + cairo_set_line_width(cairo_, width); + { + auto center = outline_rect.GetCenter(); + cairo_matrix_t save_matrix; + cairo_get_matrix(cairo_, &save_matrix); + cairo_translate(cairo_, center.x, center.y); + cairo_scale(cairo_, 1, outline_rect.height / outline_rect.width); + cairo_translate(cairo_, -center.x, -center.y); + cairo_new_path(cairo_); + cairo_arc(cairo_, center.x, center.y, outline_rect.width / 2.0, 0, + 2 * M_PI); + cairo_set_matrix(cairo_, &save_matrix); + } + cairo_stroke(cairo_); + cairo_restore(cairo_); +} + +void CairoPainter::FillEllipse(const Rect& outline_rect, IBrush* brush) { + CheckValidation(); + auto cairo_brush = CheckPlatform<CairoBrush>(brush, GetPlatformId()); + auto cairo_pattern = cairo_brush->GetCairoPattern(); + cairo_save(cairo_); + cairo_set_source(cairo_, cairo_pattern); + { + auto center = outline_rect.GetCenter(); + cairo_matrix_t save_matrix; + cairo_get_matrix(cairo_, &save_matrix); + cairo_translate(cairo_, center.x, center.y); + cairo_scale(cairo_, 1, outline_rect.height / outline_rect.width); + cairo_translate(cairo_, -center.x, -center.y); + cairo_new_path(cairo_); + cairo_arc(cairo_, center.x, center.y, outline_rect.width / 2.0, 0, + 2 * M_PI); + cairo_set_matrix(cairo_, &save_matrix); + } + cairo_fill(cairo_); + cairo_restore(cairo_); +} + +void CairoPainter::StrokeGeometry(IGeometry* geometry, IBrush* brush, + float width) { + CheckValidation(); + auto cairo_geometry = CheckPlatform<CairoGeometry>(geometry, GetPlatformId()); + auto cairo_brush = CheckPlatform<CairoBrush>(brush, GetPlatformId()); + + auto cairo_path = cairo_geometry->GetCairoPath(); + auto cairo_pattern = cairo_brush->GetCairoPattern(); + + cairo_save(cairo_); + cairo_set_source(cairo_, cairo_pattern); + cairo_set_line_width(cairo_, width); + cairo_new_path(cairo_); + cairo_append_path(cairo_, cairo_path); + cairo_stroke(cairo_); + cairo_restore(cairo_); +} + +void CairoPainter::FillGeometry(IGeometry* geometry, IBrush* brush) { + CheckValidation(); + auto cairo_geometry = CheckPlatform<CairoGeometry>(geometry, GetPlatformId()); + auto cairo_brush = CheckPlatform<CairoBrush>(brush, GetPlatformId()); + + auto cairo_path = cairo_geometry->GetCairoPath(); + auto cairo_pattern = cairo_brush->GetCairoPattern(); + + cairo_save(cairo_); + cairo_set_source(cairo_, cairo_pattern); + cairo_new_path(cairo_); + cairo_append_path(cairo_, cairo_path); + cairo_fill(cairo_); + cairo_restore(cairo_); +} + +void CairoPainter::DrawText(const Point& offset, ITextLayout* text_layout, + IBrush* brush) { + CheckValidation(); + + auto pango_text_layout = + CheckPlatform<PangoTextLayout>(text_layout, GetPlatformId()); + + auto cairo_brush = CheckPlatform<CairoBrush>(brush, GetPlatformId()); + auto cairo_pattern = cairo_brush->GetCairoPattern(); + + cairo_save(cairo_); + cairo_set_source(cairo_, cairo_pattern); + pango_cairo_show_layout(cairo_, pango_text_layout->GetPangoLayout()); + cairo_restore(cairo_); +} + +void CairoPainter::DrawImage(const Point& offset, IImage* image) { + throw Exception(u"Not implemented."); +} + +void CairoPainter::PushLayer(const Rect& bounds) { + CheckValidation(); + layer_stack_.push_back(bounds); + cairo_reset_clip(cairo_); + cairo_new_path(cairo_); + cairo_rectangle(cairo_, bounds.left, bounds.top, bounds.width, bounds.height); + cairo_clip(cairo_); +} + +void CairoPainter::PopLayer() { + CheckValidation(); + layer_stack_.pop_back(); + cairo_reset_clip(cairo_); + if (!layer_stack_.empty()) { + auto clip = layer_stack_.back(); + cairo_new_path(cairo_); + cairo_rectangle(cairo_, clip.left, clip.top, clip.width, clip.height); + cairo_clip(cairo_); + } +} + +void CairoPainter::PushState() { + CheckValidation(); + cairo_save(cairo_); +} + +void CairoPainter::PopState() { + CheckValidation(); + cairo_restore(cairo_); +} + +void CairoPainter::EndDraw() { valid_ = false; } + void CairoPainter::CheckValidation() { if (!valid_) { throw ReuseException(u"Painter already ended drawing."); |