diff options
Diffstat (limited to 'src/platform')
-rw-r--r-- | src/platform/graphics/cairo/CMakeLists.txt | 6 | ||||
-rw-r--r-- | src/platform/graphics/cairo/CairoPainter.cpp | 183 |
2 files changed, 187 insertions, 2 deletions
diff --git a/src/platform/graphics/cairo/CMakeLists.txt b/src/platform/graphics/cairo/CMakeLists.txt index c1a2a4b5..d61cdc77 100644 --- a/src/platform/graphics/cairo/CMakeLists.txt +++ b/src/platform/graphics/cairo/CMakeLists.txt @@ -6,6 +6,8 @@ if (UNIX) find_library(LIB_CAIRO cairo REQUIRED) find_library(LIB_GOBJECT NAMES gobject gobject-2.0 REQUIRED) find_library(LIB_PANGO NAMES pango pango-1.0 REQUIRED) + find_library(LIB_PANGOCAIRO NAMES pangocairo pangocairo-1.0.0 REQUIRED) + find_path(CAIRO_HEADER_DIR NAMES cairo.h PATH_SUFFIXES cairo REQUIRED) find_path(GLIB_HEADER_DIR NAMES glib.h PATH_SUFFIXES glib glib-2.0 REQUIRED) find_path(GLIBCONFIG_HEADER_DIR NAMES glibconfig.h HINTS ${LIB_ARCH_DIR} PATH_SUFFIXES glib glib/include glib-2.0 glib-2.0/include REQUIRED) find_path(HARFBUZZ_HEADER_DIR NAMES hb.h PATH_SUFFIXES harfbuzz REQUIRED) @@ -22,6 +24,6 @@ if (UNIX) PangoTextLayout.cpp ) target_compile_definitions(CruPlatformGraphicsCairo PRIVATE CRU_PLATFORM_GRAPHICS_CAIRO_EXPORT_API) - target_link_libraries(CruPlatformGraphicsCairo PUBLIC CruPlatformGraphics PUBLIC ${LIB_GOBJECT} ${LIB_CAIRO} ${LIB_PANGO}) - target_include_directories(CruPlatformGraphicsCairo PUBLIC ${GLIB_HEADER_DIR} ${GLIBCONFIG_HEADER_DIR} ${HARFBUZZ_HEADER_DIR} ${PANGO_HEADER_DIR}) + target_link_libraries(CruPlatformGraphicsCairo PUBLIC CruPlatformGraphics PUBLIC ${LIB_GOBJECT} ${LIB_CAIRO} ${LIB_PANGO} ${LIB_PANGOCAIRO}) + target_include_directories(CruPlatformGraphicsCairo PUBLIC ${CAIRO_HEADER_DIR} ${GLIB_HEADER_DIR} ${GLIBCONFIG_HEADER_DIR} ${HARFBUZZ_HEADER_DIR} ${PANGO_HEADER_DIR}) endif() 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."); |