/** Evaluates the special dvisvgm:bbox. * variant 1: dvisvgm:bbox [r[el]] <width> <height> [<depth>] [transform] * variant 2: dvisvgm:bbox a[bs] <x1> <y1> <x2> <y2> [transform] * variant 3: dvisvgm:bbox f[ix] <x1> <y1> <x2> <y2> [transform] * variant 4: dvisvgm:bbox n[ew] <name> * variant 5: dvisvgm:bbox lock | unlock */ void DvisvgmSpecialHandler::processBBox (InputReader &ir, SpecialActions &actions) { ir.skipSpace(); if (ir.check("lock")) actions.bbox().lock(); else if (ir.check("unlock")) actions.bbox().unlock(); else { int c = ir.peek(); try { if (!isalpha(c)) c = 'r'; // no mode specifier => relative box parameters else { while (!isspace(ir.peek())) // skip trailing characters ir.get(); if (c == 'n') { // "new": create new local bounding box ir.skipSpace(); string name; while (isalnum(ir.peek())) name += char(ir.get()); ir.skipSpace(); if (!name.empty() && ir.eof()) actions.bbox(name, true); // create new user box } else if (c == 'a' || c == 'f') { // "abs" or "fix" Length lengths[4]; for (Length &len : lengths) len = read_length(ir); BoundingBox b(lengths[0], lengths[1], lengths[2], lengths[3]); ir.skipSpace(); if (ir.check("transform")) b.transform(actions.getMatrix()); if (c == 'a') actions.embed(b); else { actions.bbox() = b; actions.bbox().lock(); } } } if (c == 'r') { Length w = read_length(ir); Length h = read_length(ir); Length d = read_length(ir); ir.skipSpace(); update_bbox(w, h, d, ir.check("transform"), actions); } } catch (const UnitException &e) { throw SpecialException(string("dvisvgm:bbox: ") + e.what()); } } }
void DvisvgmSpecialHandler::dviEndPage (unsigned, SpecialActions &actions) { _defsParser.flush(actions); _pageParser.flush(actions); actions.bbox().unlock(); for (auto &strvecpair : _macros) { StringVector &vec = strvecpair.second; for (string &str : vec) { // activate locked parts of a pattern again if (str[0] == 'L') str[0] = 'D'; } } }
/** Applies the previously recorded size to a given page. */ void PapersizeSpecialHandler::applyPaperSize (unsigned pageno, SpecialActions &actions) { // find page n >= pageno that contains a papersize special auto lb_it = lower_bound(_pageSizes.begin(), _pageSizes.end(), PageSize(pageno, DoublePair()), [](const PageSize &ps1, const PageSize &ps2) { // order PageSize objects by page number return ps1.first < ps2.first; }); auto it = _pageSizes.end(); if (lb_it != _pageSizes.end() && lb_it->first == pageno) it = lb_it; // if current page contains a papersize special, use it else if (lb_it != _pageSizes.begin()) // no papersize special on current page? it = lb_it-1; // => use the one on the nearest preceding page if (it == _pageSizes.end()) Message::wstream(true) << "no valid papersize special found\n"; else { DoublePair size = it->second; const double border = -72; // DVI standard: coordinates of upper left paper corner are (-72bp, -72bp) actions.bbox() = BoundingBox(border, border, size.first+border, size.second+border); } }
/** Replaces constants of the form {?name} by their corresponding value. * @param[in,out] str text to expand * @param[in] actions interfcae to the world outside the special handler */ static void expand_constants (string &str, SpecialActions &actions) { bool repl_bbox = true; while (repl_bbox) { size_t pos = str.find("{?bbox "); if (pos == string::npos) repl_bbox = false; else { size_t endpos = pos+7; while (endpos < str.length() && isalnum(str[endpos])) ++endpos; if (str[endpos] == '}') { BoundingBox &box=actions.bbox(str.substr(pos+7, endpos-pos-7)); str.replace(pos, endpos-pos+1, box.toSVGViewBox()); } else repl_bbox = false; } } struct Constant { const char *name; string val; }; const array<Constant, 5> constants {{ {"x", XMLString(actions.getX())}, {"y", XMLString(actions.getY())}, {"color", actions.getColor().svgColorString()}, {"matrix", actions.getMatrix().toSVG()}, {"nl", "\n"}, }}; for (const Constant &constant : constants) { const string pattern = string("{?")+constant.name+"}"; size_t pos = str.find(pattern); while (pos != string::npos) { str.replace(pos, strlen(constant.name)+3, constant.val); pos = str.find(pattern, pos+constant.val.length()); // look for further matches } } }