From f4b08fb9511347c038a3a474ab7bdc073e75baff Mon Sep 17 00:00:00 2001
From: Přemysl Eric Janouch 
Date: Sun, 12 Jan 2025 10:00:32 +0100
Subject: lpg: improve Picture sizing, clean up
Restraining a Picture in one dimension with a Frame should make it
report the right overall dimensions (keeping its aspect ratio).
Also applying the F.9 C++ Core Guideline.
---
 lpg/lpg.cpp | 68 ++++++++++++++++++++++++++++++++++++++++---------------------
 1 file changed, 45 insertions(+), 23 deletions(-)
(limited to 'lpg')
diff --git a/lpg/lpg.cpp b/lpg/lpg.cpp
index 0301945..341a104 100644
--- a/lpg/lpg.cpp
+++ b/lpg/lpg.cpp
@@ -88,8 +88,8 @@ struct Widget {
 	}
 
 	/// Render to the context within the designated space, no clipping.
-	virtual void render([[maybe_unused]] cairo_t *cr, [[maybe_unused]] double w,
-		[[maybe_unused]] double h) {}
+	virtual void render([[maybe_unused]] cairo_t *cr,
+		[[maybe_unused]] double w, [[maybe_unused]] double h) {}
 };
 
 /// Special container that basically just fucks with the system right now.
@@ -111,6 +111,20 @@ DefWidget(Frame) {
 		return d;
 	}
 
+	virtual tuple prepare_for_size(
+		PangoContext *pc, double width, double height) override {
+		if (auto v = getattr("w_override"); v && get(*v) >= 0)
+			width = get(*v);
+		if (auto v = getattr("h_override"); v && get(*v) >= 0)
+			height = get(*v);
+		auto d = child->prepare_for_size(pc, width, height);
+		if (auto v = getattr("w_override"))
+			get<0>(d) = get(*v);
+		if (auto v = getattr("h_override"))
+			get<1>(d) = get(*v);
+		return d;
+	}
+
 	virtual void render(cairo_t *cr, double w, double h) override {
 		cairo_save(cr);
 
@@ -252,8 +266,7 @@ DefContainer(VBox) {
 DefWidget(Filler) {
 	double w, h;
 	Filler(double w = -1, double h = -1) : w(w), h(h) {}
-	virtual tuple prepare(
-		[[maybe_unused]] PangoContext *pc) override {
+	virtual tuple prepare(PangoContext *) override {
 		return {w, h};
 	}
 };
@@ -261,8 +274,7 @@ DefWidget(Filler) {
 DefWidget(HLine) {
 	double thickness;
 	HLine(double thickness = 1) : thickness(thickness) {}
-	virtual tuple prepare(
-		[[maybe_unused]] PangoContext *pc) override {
+	virtual tuple prepare(PangoContext *) override {
 		return {-1, thickness};
 	}
 	virtual void render(cairo_t *cr, double w, double h) override {
@@ -276,8 +288,7 @@ DefWidget(HLine) {
 DefWidget(VLine) {
 	double thickness;
 	VLine(double thickness = 1) : thickness(thickness) {}
-	virtual tuple prepare(
-		[[maybe_unused]] PangoContext *pc) override {
+	virtual tuple prepare(PangoContext *) override {
 		return {thickness, -1};
 	}
 	virtual void render(cairo_t *cr, double w, double h) override {
@@ -355,8 +366,8 @@ DefWidget(Text) {
 			double(w) / PANGO_SCALE, double(h) / PANGO_SCALE + 2 * y_offset};
 	}
 
-	virtual tuple prepare_for_size(PangoContext *pc,
-		double width, [[maybe_unused]] double height) override {
+	virtual tuple prepare_for_size(
+		PangoContext *pc, double width, double) override {
 		prepare_layout(pc);
 
 		// It's difficult to get vertical text, so wrap horizontally.
@@ -368,7 +379,7 @@ DefWidget(Text) {
 			double(w) / PANGO_SCALE, double(h) / PANGO_SCALE + 2 * y_offset};
 	}
 
-	virtual void render(cairo_t *cr, double w, [[maybe_unused]] double h)
+	virtual void render(cairo_t *cr, double w, double)
 		override {
 		g_return_if_fail(layout);
 		// Assuming horizontal text, make it span the whole allocation.
@@ -424,20 +435,33 @@ DefWidget(Picture) {
 	double scale_x = 1., scale_y = 1.;
 	cairo_surface_t *surface = nullptr;
 
+	double postscale_for(double width, double height) {
+		double w = this->w * scale_x;
+		double h = this->h * scale_y;
+		if (w < 0 || h < 0)
+			return 1;
+
+		double postscale = width / w;
+		if (h * postscale > height)
+			postscale = height / h;
+		return postscale;
+	}
+
 	virtual tuple prepare(PangoContext *) override {
 		return {w * scale_x, h * scale_y};
 	}
 
+	virtual tuple prepare_for_size(
+		PangoContext *pc, double width, double height) override {
+		auto d = prepare(pc);
+		auto postscale = postscale_for(width, height);
+		return {get<0>(d) * postscale, get<1>(d) * postscale};
+	}
+
 	virtual void render(cairo_t *cr, double width, double height) override {
 		if (!surface || width <= 0 || height <= 0)
 			return;
 
-		double ww = this->w * scale_x;
-		double hh = this->h * scale_y;
-		double postscale = width / ww;
-		if (hh * postscale > height)
-			postscale = height / hh;
-
 		// For PDF-A, ISO 19005-3:2012 6.2.8: interpolation is not allowed
 		// (Cairo sets it on by default).
 		bool interpolate = true;
@@ -447,6 +471,7 @@ DefWidget(Picture) {
 			pattern, interpolate ? CAIRO_FILTER_GOOD : CAIRO_FILTER_NEAREST);
 
 		// Maybe we should also center the picture or something...
+		auto postscale = postscale_for(width, height);
 		cairo_scale(cr, scale_x * postscale, scale_y * postscale);
 		cairo_set_source(cr, pattern);
 		cairo_paint(cr);
@@ -524,16 +549,14 @@ DefWidget(QR) {
 			QRcode_free(code);
 	}
 
-	virtual tuple prepare([[maybe_unused]] PangoContext *pc)
-		override {
+	virtual tuple prepare(PangoContext *) override {
 		if (!code)
 			return {0, 0};
 
 		return {T * code->width, T * code->width};
 	}
 
-	virtual void render(cairo_t *cr,
-		[[maybe_unused]] double w, [[maybe_unused]] double h) override {
+	virtual void render(cairo_t *cr, double, double) override {
 		if (!code)
 			return;
 
@@ -1062,8 +1085,7 @@ static int xlua_error_handler(lua_State *L) {
 	return 1;
 }
 
-static void *xlua_alloc([[maybe_unused]] void *ud, void *ptr,
-	[[maybe_unused]] size_t o_size, size_t n_size) {
+static void *xlua_alloc(void *, void *ptr, size_t, size_t n_size) {
 	if (n_size)
 		return realloc(ptr, n_size);
 
-- 
cgit v1.2.3-70-g09d2