+// Paper specifications
+
+class paper_spec {
+public:
+ double w, h;
+ paper_spec(cmd *c, bool maybe=true)
+ {
+ arg_val *aname = c->arg("paper");
+ arg_val *aw = c->arg("w");
+ arg_val *ah = c->arg("h");
+ if (!aname->given() && !aw->given() && !ah->given() && maybe)
+ {
+ w = h = 0;
+ return;
+ }
+ if (aw->given() != ah->given() || aname->given() == aw->given())
+ die("Either paper format name or width and height must be given");
+ if (aname->given())
+ {
+ const char *name = aname->as_string("").c_str();
+ const paper *pap = paperinfo(name);
+ if (!pap)
+ die("No paper called %s is known", name);
+ w = paperpswidth(pap);
+ h = paperpsheight(pap);
+ }
+ else
+ {
+ w = aw->as_double(0);
+ h = ah->as_double(0);
+ }
+ }
+};
+
+#define PAPER_ARGS \
+ { "paper", AT_STRING | AT_POSITIONAL }, \
+ { "w", AT_DIMEN }, \
+ { "h", AT_DIMEN }
+
+// Position specification
+
+class pos_spec {
+public:
+ int h, v;
+ pos_spec() { v = h = 0; }
+ pos_spec(string s)
+ {
+ if (s.size() != 2)
+ die("Value of pos must have two characters");
+ if (s[0] == 't')
+ v = 1;
+ else if (s[0] == 'c')
+ v = 0;
+ else if (s[0] == 'b')
+ v = -1;
+ else
+ die("First character of pos must be t/c/b");
+ if (s[1] == 'l')
+ h = -1;
+ else if (s[1] == 'c')
+ h = 0;
+ else if (s[1] == 'r')
+ h = 1;
+ else
+ die("Second character of pos must be l/c/r");
+ }
+ pos_spec(cmd *c) : pos_spec(c->arg("pos")->as_string("cc")) { }
+ pdf_matrix place(BBox &inner, BBox &outer)
+ {
+ pdf_matrix m;
+ m.shift(-inner.x_min, -inner.y_min);
+ switch (h)
+ {
+ case -1:
+ break;
+ case 0:
+ m.shift((outer.width() - inner.width()) / 2, 0);
+ break;
+ case 1:
+ m.shift(outer.width() - inner.width(), 0);
+ break;
+ default:
+ abort();
+ }
+ switch (v)
+ {
+ case -1:
+ break;
+ case 0:
+ m.shift(0, (outer.height() - inner.height()) / 2);
+ break;
+ case 1:
+ m.shift(0, outer.height() - inner.height());
+ break;
+ default:
+ abort();
+ }
+ m.shift(outer.x_min, outer.y_min);
+ return m;
+ }
+};
+
+#define POS_ARGS \
+ { "pos", AT_STRING }
+
+// Margins
+
+class margin_spec {
+public:
+ double l, r, t, b;
+ margin_spec(cmd *c, string basic, string sx)
+ {
+ double m, h, v;
+ m = c->arg(basic)->as_double(0);
+ h = c->arg("h" + sx)->as_double(m);
+ v = c->arg("v" + sx)->as_double(m);
+ l = c->arg("l" + sx)->as_double(h);
+ r = c->arg("r" + sx)->as_double(h);
+ t = c->arg("t" + sx)->as_double(v);
+ b = c->arg("b" + sx)->as_double(v);
+ }
+ void shrink_box(BBox *bb)
+ {
+ bb->x_min += l;
+ bb->x_max -= r;
+ bb->y_min += b;
+ bb->y_max -= t;
+ if (bb->x_min >= bb->x_max || bb->y_min >= bb->y_max)
+ die("Margins cannot be larger than the whole page");
+ }
+ void expand_box(BBox *bb)
+ {
+ bb->x_min -= l;
+ bb->x_max += r;
+ bb->y_min -= b;
+ bb->y_max += t;
+ }
+};
+
+#define MARGIN_ARGS(basic, sx) \
+ { basic, AT_DIMEN }, \
+ { "h" sx, AT_DIMEN }, \
+ { "v" sx, AT_DIMEN }, \
+ { "l" sx, AT_DIMEN }, \
+ { "r" sx, AT_DIMEN }, \
+ { "t" sx, AT_DIMEN }, \
+ { "b" sx, AT_DIMEN }
+
+// Scaling preserving aspect ratio
+
+double scale_to_fit(BBox &from, BBox &to)
+{
+ double fw = from.width(), fh = from.height();
+ double tw = to.width(), th = to.height();
+ if (is_zero(fw) || is_zero(fh) || is_zero(tw) || is_zero(th))
+ return 1;
+ else
+ return min(tw/fw, th/fh);
+}
+