/** Reads a length value including a trailing unit specifier and returns it. */ static Length read_length (InputReader &ir) { Length length; ir.skipSpace(); if (!isalpha(ir.peek())) { double val = ir.getDouble(); string unit = isalpha(ir.peek()) ? ir.getString(2) : "pt"; length = Length(val, unit); } return length; }
/** 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()); } } }
static string read_entry (InputReader &in) { string entry; bool accept_slashes=true; while (!in.eof() && ((in.peek() == '/' && accept_slashes) || valid_name_char(in.peek()))) { if (in.peek() != '/') accept_slashes = false; entry += char(in.get()); } if (entry.length() > 1) { // strip leading slashes // According to the PostScript specification, a single slash without further // following characters is a valid name. size_t n=0; while (n < entry.length() && entry[n] == '/') n++; entry = entry.substr(n); } return entry; }
/** Evaluates the special dvisvgm:bbox. * variant 1: dvisvgm:bbox [r[el]] <width> <height> [<depth>] * variant 2: dvisvgm:bbox a[bs] <x1> <y1> <x2> <y2> * variant 3: dvisvgm:bbox f[ix] <x1> <y1> <x2> <y2> * variant 4: dvisvgm:bbox n[ew] <name> */ void DvisvgmSpecialHandler::processBBox (InputReader &ir, SpecialActions *actions) { const double pt2bp = 72/72.27; ir.skipSpace(); int c = ir.peek(); if (isalpha(c)) { while (!isspace(ir.peek())) // skip trailing characters ir.get(); if (c == 'n') { 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') { double p[4]; for (int i=0; i < 4; i++) p[i] = ir.getDouble()*pt2bp; BoundingBox b(p[0], p[1], p[2], p[3]); if (c == 'a') actions->embed(b); else { actions->bbox() = b; actions->bbox().lock(); } } } else c = 'r'; // no mode specifier => relative box parameters if (c == 'r') { double w = ir.getDouble()*pt2bp; double h = ir.getDouble()*pt2bp; double d = ir.getDouble()*pt2bp; update_bbox(w, h, d, actions); } }
/** Reads a length (value + unit) and returns its value in PS points (bp). * If no unit is specified, TeX points are assumed. */ static double read_length (InputReader &in) { double val = in.getDouble(); string unitstr; if (isalpha(in.peek())) unitstr += in.get(); if (isalpha(in.peek())) unitstr += in.get(); Length::Unit unit = Length::Unit::PT; try { unit = Length::stringToUnit(unitstr); } catch (UnitException &e) { } return Length(val, unit).bp(); }
/** Handles the "line" command that draws a straight line between two points * from the point list. */ void EmSpecialHandler::line (InputReader &ir, SpecialActions& actions) { int pointnum1 = ir.getInt(); int cut1 = 'p'; if (isalpha(ir.peek())) cut1 = ir.get(); ir.getPunct(); int pointnum2 = ir.getInt(); int cut2 = 'p'; if (isalpha(ir.peek())) cut2 = ir.get(); double linewidth = _linewidth; if (ir.getPunct() == ',') linewidth = read_length(ir); auto it1=_points.find(pointnum1); auto it2=_points.find(pointnum2); if (it1 != _points.end() && it2 != _points.end()) create_line(it1->second, it2->second, char(cut1), char(cut2), linewidth, actions); else { // Line endpoints don't necessarily have to be defined before // a line definition. If a point isn't defined yet, we put the line // in a wait list and process the lines at the end of the page. _lines.emplace_back(Line(pointnum1, pointnum2, char(cut1), char(cut2), linewidth)); } }
/** Parses a single line in dvips mapfile format. * @param[in] ir the input stream must be assigned to this reader */ void MapLine::parseDVIPSLine (InputReader &ir) { ir.skipSpace(); if (ir.peek() != '<' && ir.peek() != '"') _psname = ir.getString(); ir.skipSpace(); while (ir.peek() == '<' || ir.peek() == '"') { if (ir.peek() == '<') { ir.get(); if (ir.peek() == '[') ir.get(); string name = ir.getString(); if (name.length() > 4 && name.substr(name.length()-4) == ".enc") _encname = name.substr(0, name.length()-4); else _fontfname = name; } else { // ir.peek() == '"' => list of PS font operators string options = ir.getQuotedString('"'); StringInputBuffer sib(options); BufferInputReader sir(sib); while (!sir.eof()) { double number; if (sir.parseDouble(number)) { // operator with preceding numeric parameter (value opstr) string opstr = sir.getString(); if (opstr == "SlantFont") _slant = number; else if (opstr == "ExtendFont") _extend = number; } else { // operator without parameter => skip for now sir.getString(); } } } ir.skipSpace(); } }
/** Parses a single line in dvipdfmx mapfile format. * @param[in] ir the input stream must be assigned to this reader */ void MapLine::parseDVIPDFMLine (InputReader &ir) { ir.skipSpace(); if (ir.peek() != '-') { _encname = ir.getString(); if (_encname == "default" || _encname == "none") _encname.clear(); } ir.skipSpace(); if (ir.peek() != '-') _fontfname = ir.getString(); if (!_fontfname.empty()) { parseFilenameOptions(_fontfname); } ir.skipSpace(); while (ir.peek() == '-') { ir.get(); int option = ir.get(); if (!isprint(option)) throw MapLineException("option character expected"); ir.skipSpace(); switch (option) { case 's': // slant if (!ir.parseDouble(_slant)) throw_number_expected('s'); break; case 'e': // extend if (!ir.parseDouble(_extend)) throw_number_expected('e'); break; case 'b': // bold if (!ir.parseDouble(_bold)) throw_number_expected('b'); break; case 'r': //remap (deprecated) break; case 'i': // ttc index if (!ir.parseInt(_fontindex, false)) throw_number_expected('i', true); break; case 'p': // UCS plane int dummy; if (!ir.parseInt(dummy, false)) throw_number_expected('p', true); break; case 'u': // to unicode ir.getString(); break; case 'v': // stemV int stemv; if (!ir.parseInt(stemv, true)) throw_number_expected('v', true); break; case 'm': // map single chars ir.skipUntil("-"); break; case 'w': // writing mode (horizontal=0, vertical=1) int vertical; if (!ir.parseInt(vertical, false)) throw_number_expected('w', true); break; default: ostringstream oss; oss << "invalid option: -" << option; throw MapLineException(oss.str()); } ir.skipSpace(); } }