aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/platform/graphics/cairo/CMakeLists.txt6
-rw-r--r--src/platform/graphics/cairo/CairoPainter.cpp183
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.");