| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175 |
- // Copyright ©2021 The star-tex Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style
- // license that can be found in the LICENSE-STAR-TEX file.
- package dvi
- import (
- "errors"
- "fmt"
- "io"
- "sort"
- "strings"
- "modernc.org/knuth/font/fixed"
- "modernc.org/knuth/font/tfm"
- "modernc.org/knuth/kpath"
- )
- const (
- maxdrift = 2
- )
- // Machine defines a DVI machine, handling DVI registers and DVI commands.
- type Machine struct {
- rdr Renderer
- ktx kpath.Context
- state state
- conv float32 // converts DVI units to pixels
- trueConv float32 // converts unmagnified DVI units to pixels
- xoff int32 // width offset
- yoff int32 // height offset
- w io.Writer
- buf []byte // 80-col buffer of text
- handlers []Handler // list of registered special handlers for CmdXXXn commands.
- color colorHandler // special handling of colors
- }
- // NewMachine creates a new DVI machine.
- func NewMachine(opts ...Option) Machine {
- cfg := newConfig()
- for _, opt := range opts {
- err := opt(cfg)
- if err != nil {
- panic(err)
- }
- }
- m := Machine{
- ktx: cfg.ctx,
- rdr: cfg.rdr,
- state: newState(),
- xoff: cfg.xoff,
- yoff: cfg.yoff,
- w: cfg.out,
- buf: make([]byte, 0, 80-len("[]\n")),
- handlers: cfg.handlers,
- color: nilColorHandler{},
- }
- for _, h := range m.handlers {
- if hh, ok := h.(colorHandler); ok {
- m.color = hh
- break
- }
- }
- return m
- }
- // Run executes the whole DVI program on this DVI machine.
- func (m *Machine) Run(p Program) error {
- m.load(p)
- for i := range p.pages {
- err := m.run(p, i)
- if err != nil {
- return fmt.Errorf("dvi: could not process page %d: %w", i+1, err)
- }
- }
- return nil
- }
- func (m *Machine) load(p Program) {
- m.printf("numerator/denominator=%d/%d\n", p.pre.Num, p.pre.Den)
- res := float32(300.0)
- conv := float32(p.pre.Num) / 254000.0 * (res / float32(p.pre.Den))
- m.trueConv = conv
- m.conv = conv * float32(p.pre.Mag) / 1000.0
- m.printf("magnification=%d; %16.8f pixels per DVI unit\n", p.pre.Mag, m.conv)
- m.printf("'%s'\n", p.pre.Msg)
- m.printf("Postamble starts at byte %d.\n", p.ppost)
- m.printf("maxv=%d, maxh=%d, maxstackdepth=%d, totalpages=%d\n",
- p.post.Height, p.post.Width, p.post.MaxStack,
- p.post.Pages,
- )
- m.state.fonts = p.fonts
- fonts := make([]int, 0, len(p.fonts))
- for id := range p.fonts {
- fonts = append(fonts, id)
- }
- sort.Sort(sort.Reverse(sort.IntSlice(fonts)))
- for _, id := range fonts {
- fnt := m.state.fonts[id]
- m.printf(
- "Font %d: %s---loaded at size %d DVI units \n",
- id, fnt.Name, fnt.Size,
- )
- }
- }
- func (m *Machine) run(p Program, ip int) error {
- var (
- beg = int(p.pages[ip].beg)
- end = int(p.pages[ip].end)
- eop = false
- )
- m.rdr.Init(&p.pre, &p.post)
- p.r.SetPos(beg)
- op := opCode(p.r.PeekU8())
- if op != opBOP {
- return errNoBOP
- }
- bop := op.cmd().(*CmdBOP)
- bop.read(p.r)
- m.state.reset(m.xoff, m.yoff, m.pixels)
- m.printf(" \n%d: beginning of page %d \n", beg, bop.C0)
- m.rdr.BOP(bop)
- for p.r.Pos() < end {
- pos := p.r.Pos()
- switch op := opCode(p.r.PeekU8()); op {
- case opBOP, opPre, opPost, opPostPost:
- return fmt.Errorf("dvi: invalid opcode=%s inside a page", op.cmd().Name())
- case opEOP:
- eop = true
- m.flushText()
- m.printf("%d: eop", pos)
- op.cmd().read(p.r)
- m.rdr.EOP()
- lvl := len(m.state.stack) - 1
- if lvl != 0 {
- m.printf("stack not empty at end of page (level %d)!\n", lvl)
- }
- case opSetChar000, opSetChar001, opSetChar002, opSetChar003, opSetChar004,
- opSetChar005, opSetChar006, opSetChar007, opSetChar008, opSetChar009,
- opSetChar010, opSetChar011, opSetChar012, opSetChar013, opSetChar014,
- opSetChar015, opSetChar016, opSetChar017, opSetChar018, opSetChar019,
- opSetChar020, opSetChar021, opSetChar022, opSetChar023, opSetChar024,
- opSetChar025, opSetChar026, opSetChar027, opSetChar028, opSetChar029,
- opSetChar030, opSetChar031, opSetChar032, opSetChar033, opSetChar034,
- opSetChar035, opSetChar036, opSetChar037, opSetChar038, opSetChar039,
- opSetChar040, opSetChar041, opSetChar042, opSetChar043, opSetChar044,
- opSetChar045, opSetChar046, opSetChar047, opSetChar048, opSetChar049,
- opSetChar050, opSetChar051, opSetChar052, opSetChar053, opSetChar054,
- opSetChar055, opSetChar056, opSetChar057, opSetChar058, opSetChar059,
- opSetChar060, opSetChar061, opSetChar062, opSetChar063, opSetChar064,
- opSetChar065, opSetChar066, opSetChar067, opSetChar068, opSetChar069,
- opSetChar070, opSetChar071, opSetChar072, opSetChar073, opSetChar074,
- opSetChar075, opSetChar076, opSetChar077, opSetChar078, opSetChar079,
- opSetChar080, opSetChar081, opSetChar082, opSetChar083, opSetChar084,
- opSetChar085, opSetChar086, opSetChar087, opSetChar088, opSetChar089,
- opSetChar090, opSetChar091, opSetChar092, opSetChar093, opSetChar094,
- opSetChar095, opSetChar096, opSetChar097, opSetChar098, opSetChar099,
- opSetChar100, opSetChar101, opSetChar102, opSetChar103, opSetChar104,
- opSetChar105, opSetChar106, opSetChar107, opSetChar108, opSetChar109,
- opSetChar110, opSetChar111, opSetChar112, opSetChar113, opSetChar114,
- opSetChar115, opSetChar116, opSetChar117, opSetChar118, opSetChar119,
- opSetChar120, opSetChar121, opSetChar122, opSetChar123, opSetChar124,
- opSetChar125, opSetChar126, opSetChar127:
- cmd := op.cmd().(*CmdSetChar)
- cmd.read(p.r)
- switch {
- case cmd.Value > ' ' && cmd.Value <= '~':
- m.outText(cmd.Value)
- default:
- m.flushText()
- }
- m.printf("%d: %s", pos, strings.Replace(cmd.Name(), "_", "", -1))
- err := m.drawGlyph(cmd.opcode(), int32(cmd.Value))
- if err != nil {
- return fmt.Errorf("could not set char %q: %w", op, err)
- }
- case opSet1:
- cmd := op.cmd().(*CmdSet1)
- cmd.read(p.r)
- m.flushText()
- m.printf("%d: set1 %d", pos, cmd.Value)
- err := m.drawGlyph(cmd.opcode(), int32(cmd.Value))
- if err != nil {
- return fmt.Errorf("could not set1: %w", err)
- }
- case opSet2:
- cmd := op.cmd().(*CmdSet2)
- cmd.read(p.r)
- m.flushText()
- m.printf("%d: set2 %d", pos, cmd.Value)
- err := m.drawGlyph(cmd.opcode(), int32(cmd.Value))
- if err != nil {
- return fmt.Errorf("could not set2: %w", err)
- }
- case opSet3:
- cmd := op.cmd().(*CmdSet3)
- cmd.read(p.r)
- m.flushText()
- m.printf("%d: set3 %d", pos, cmd.Value)
- err := m.drawGlyph(cmd.opcode(), int32(cmd.Value))
- if err != nil {
- return fmt.Errorf("could not set3: %w", err)
- }
- case opSet4:
- cmd := op.cmd().(*CmdSet4)
- cmd.read(p.r)
- m.flushText()
- m.printf("%d: set4 %d", pos, cmd.Value)
- err := m.drawGlyph(cmd.opcode(), cmd.Value)
- if err != nil {
- return fmt.Errorf("could not set4: %w", err)
- }
- case opSetRule:
- cmd := op.cmd().(*CmdSetRule)
- cmd.read(p.r)
- m.flushText()
- m.printf("%d: setrule", pos)
- err := m.drawRule(cmd.opcode(), cmd.Height, cmd.Width)
- if err != nil {
- return fmt.Errorf("could not setrule(%d, %d): %w", cmd.Height, cmd.Width, err)
- }
- case opPut1:
- cmd := op.cmd().(*CmdPut1)
- cmd.read(p.r)
- m.flushText()
- m.printf("%d: put1 %d", pos, cmd.Value)
- err := m.drawGlyph(cmd.opcode(), int32(cmd.Value))
- if err != nil {
- return fmt.Errorf("could not put1(%d): %w", cmd.Value, err)
- }
- case opPut2:
- cmd := op.cmd().(*CmdPut2)
- cmd.read(p.r)
- m.flushText()
- m.printf("%d: put2 %d", pos, cmd.Value)
- err := m.drawGlyph(cmd.opcode(), int32(cmd.Value))
- if err != nil {
- return fmt.Errorf("could not put2(%d): %w", cmd.Value, err)
- }
- case opPut3:
- cmd := op.cmd().(*CmdPut3)
- cmd.read(p.r)
- m.flushText()
- m.printf("%d: put3 %d", pos, cmd.Value)
- err := m.drawGlyph(cmd.opcode(), int32(cmd.Value))
- if err != nil {
- return fmt.Errorf("could not put3(%d): %w", cmd.Value, err)
- }
- case opPut4:
- cmd := op.cmd().(*CmdPut4)
- cmd.read(p.r)
- m.flushText()
- m.printf("%d: put4 %d", pos, cmd.Value)
- err := m.drawGlyph(cmd.opcode(), cmd.Value)
- if err != nil {
- return fmt.Errorf("could not put4(%d): %w", cmd.Value, err)
- }
- case opPutRule:
- cmd := op.cmd().(*CmdPutRule)
- cmd.read(p.r)
- m.flushText()
- m.printf("%d: putrule", pos)
- err := m.drawRule(cmd.opcode(), cmd.Height, cmd.Width)
- if err != nil {
- return fmt.Errorf("could not putrule(%d, %d): %w", cmd.Height, cmd.Width, err)
- }
- case opPush:
- m.flushText()
- m.printf("%d: push \n", pos)
- lvl := len(m.state.stack) - 1
- op.cmd().(*CmdPush).read(p.r)
- m.state.push()
- cur := m.state.cur()
- m.printf("level %d:(h=%d,v=%d,w=%d,x=%d,y=%d,z=%d,hh=%d,vv=%d)",
- lvl,
- cur.h, cur.v, cur.w, cur.x, cur.y, cur.z,
- cur.hh, cur.vv,
- )
- case opPop:
- m.flushText()
- m.printf("%d: pop \n", pos)
- op.cmd().(*CmdPop).read(p.r)
- m.state.pop()
- lvl := len(m.state.stack) - 1
- cur := m.state.cur()
- m.printf("level %d:(h=%d,v=%d,w=%d,x=%d,y=%d,z=%d,hh=%d,vv=%d)",
- lvl,
- cur.h, cur.v, cur.w, cur.x, cur.y, cur.z,
- cur.hh, cur.vv,
- )
- case opRight1:
- cmd := op.cmd().(*CmdRight1)
- cmd.read(p.r)
- cur := m.state.cur()
- cur.hh = m.outSpace(cmd.Value)
- m.printf("%d: right1 %d", pos, cmd.Value)
- err := m.moveright(cmd.Value)
- if err != nil {
- return fmt.Errorf("could not right1(%d): %w", cmd.Value, err)
- }
- case opRight2:
- cmd := op.cmd().(*CmdRight2)
- cmd.read(p.r)
- cur := m.state.cur()
- cur.hh = m.outSpace(cmd.Value)
- m.printf("%d: right2 %d", pos, cmd.Value)
- err := m.moveright(cmd.Value)
- if err != nil {
- return fmt.Errorf("could not right2(%d): %w", cmd.Value, err)
- }
- case opRight3:
- cmd := op.cmd().(*CmdRight3)
- cmd.read(p.r)
- cur := m.state.cur()
- cur.hh = m.outSpace(cmd.Value)
- m.printf("%d: right3 %d", pos, cmd.Value)
- err := m.moveright(cmd.Value)
- if err != nil {
- return fmt.Errorf("could not right3(%d): %w", cmd.Value, err)
- }
- case opRight4:
- cmd := op.cmd().(*CmdRight4)
- cmd.read(p.r)
- cur := m.state.cur()
- cur.hh = m.outSpace(cmd.Value)
- m.printf("%d: right4 %d", pos, cmd.Value)
- err := m.moveright(cmd.Value)
- if err != nil {
- return fmt.Errorf("could not right4(%d): %w", cmd.Value, err)
- }
- case opW0:
- cmd := op.cmd().(*CmdW0)
- cmd.read(p.r)
- cur := m.state.cur()
- cur.hh = m.outSpace(cur.w)
- m.printf("%d: w0 %d", pos, cur.w)
- err := m.moveright(cur.w)
- if err != nil {
- return fmt.Errorf("could not w0(%d): %w", cur.w, err)
- }
- case opW1:
- cmd := op.cmd().(*CmdW1)
- cmd.read(p.r)
- cur := m.state.cur()
- cur.w = cmd.Value
- cur.hh = m.outSpace(cmd.Value)
- m.printf("%d: w1 %d", pos, cmd.Value)
- err := m.moveright(cmd.Value)
- if err != nil {
- return fmt.Errorf("could not w1(%d): %w", cmd.Value, err)
- }
- case opW2:
- cmd := op.cmd().(*CmdW2)
- cmd.read(p.r)
- cur := m.state.cur()
- cur.w = cmd.Value
- cur.hh = m.outSpace(cmd.Value)
- m.printf("%d: w2 %d", pos, cmd.Value)
- err := m.moveright(cmd.Value)
- if err != nil {
- return fmt.Errorf("could not w2(%d): %w", cmd.Value, err)
- }
- case opW3:
- cmd := op.cmd().(*CmdW3)
- cmd.read(p.r)
- cur := m.state.cur()
- cur.w = cmd.Value
- cur.hh = m.outSpace(cmd.Value)
- m.printf("%d: w3 %d", pos, cmd.Value)
- err := m.moveright(cmd.Value)
- if err != nil {
- return fmt.Errorf("could not w3(%d): %w", cmd.Value, err)
- }
- case opW4:
- cmd := op.cmd().(*CmdW4)
- cmd.read(p.r)
- cur := m.state.cur()
- cur.w = cmd.Value
- cur.hh = m.outSpace(cmd.Value)
- m.printf("%d: w4 %d", pos, cmd.Value)
- err := m.moveright(cmd.Value)
- if err != nil {
- return fmt.Errorf("could not w4(%d): %w", cmd.Value, err)
- }
- case opX0:
- cmd := op.cmd().(*CmdX0)
- cmd.read(p.r)
- cur := m.state.cur()
- cur.hh = m.outSpace(cur.x)
- m.printf("%d: x0 %d", pos, cur.x)
- err := m.moveright(cur.x)
- if err != nil {
- return fmt.Errorf("could not x0(%d): %w", cur.x, err)
- }
- case opX1:
- cmd := op.cmd().(*CmdX1)
- cmd.read(p.r)
- cur := m.state.cur()
- cur.x = cmd.Value
- cur.hh = m.outSpace(cmd.Value)
- m.printf("%d: x1 %d", pos, cmd.Value)
- err := m.moveright(cmd.Value)
- if err != nil {
- return fmt.Errorf("could not x1(%d): %w", cmd.Value, err)
- }
- case opX2:
- cmd := op.cmd().(*CmdX2)
- cmd.read(p.r)
- cur := m.state.cur()
- cur.x = cmd.Value
- cur.hh = m.outSpace(cmd.Value)
- m.printf("%d: x2 %d", pos, cmd.Value)
- err := m.moveright(cmd.Value)
- if err != nil {
- return fmt.Errorf("could not x2(%d): %w", cmd.Value, err)
- }
- case opX3:
- cmd := op.cmd().(*CmdX3)
- cmd.read(p.r)
- cur := m.state.cur()
- cur.x = cmd.Value
- cur.hh = m.outSpace(cmd.Value)
- m.printf("%d: x3 %d", pos, cmd.Value)
- err := m.moveright(cmd.Value)
- if err != nil {
- return fmt.Errorf("could not x3(%d): %w", cmd.Value, err)
- }
- case opX4:
- cmd := op.cmd().(*CmdX4)
- cmd.read(p.r)
- cur := m.state.cur()
- cur.x = cmd.Value
- cur.hh = m.outSpace(cmd.Value)
- m.printf("%d: x4 %d", pos, cmd.Value)
- err := m.moveright(cmd.Value)
- if err != nil {
- return fmt.Errorf("could not x4(%d): %w", cmd.Value, err)
- }
- case opDown1:
- cmd := op.cmd().(*CmdDown1)
- cmd.read(p.r)
- cur := m.state.cur()
- cur.vv = m.outVMove(cmd.Value)
- m.flushText()
- m.printf("%d: down1 %d", pos, cmd.Value)
- err := m.movedown(cmd.Value)
- if err != nil {
- return fmt.Errorf("could not down1(%d): %w", cmd.Value, err)
- }
- case opDown2:
- cmd := op.cmd().(*CmdDown2)
- cmd.read(p.r)
- cur := m.state.cur()
- cur.vv = m.outVMove(cmd.Value)
- m.flushText()
- m.printf("%d: down2 %d", pos, cmd.Value)
- err := m.movedown(cmd.Value)
- if err != nil {
- return fmt.Errorf("could not down2(%d): %w", cmd.Value, err)
- }
- case opDown3:
- cmd := op.cmd().(*CmdDown3)
- cmd.read(p.r)
- cur := m.state.cur()
- cur.vv = m.outVMove(cmd.Value)
- m.flushText()
- m.printf("%d: down3 %d", pos, cmd.Value)
- err := m.movedown(cmd.Value)
- if err != nil {
- return fmt.Errorf("could not down3(%d): %w", cmd.Value, err)
- }
- case opDown4:
- cmd := op.cmd().(*CmdDown4)
- cmd.read(p.r)
- cur := m.state.cur()
- cur.vv = m.outVMove(cmd.Value)
- m.flushText()
- m.printf("%d: down4 %d", pos, cmd.Value)
- err := m.movedown(cmd.Value)
- if err != nil {
- return fmt.Errorf("could not down4(%d): %w", cmd.Value, err)
- }
- case opY0:
- cmd := op.cmd().(*CmdY0)
- cmd.read(p.r)
- cur := m.state.cur()
- cur.vv = m.outVMove(cur.y)
- m.flushText()
- m.printf("%d: y0 %d", pos, cur.y)
- err := m.movedown(cur.y)
- if err != nil {
- return fmt.Errorf("could not y0(%d): %w", cur.y, err)
- }
- case opY1:
- cmd := op.cmd().(*CmdY1)
- cmd.read(p.r)
- cur := m.state.cur()
- cur.y = cmd.Value
- cur.vv = m.outVMove(cmd.Value)
- m.flushText()
- m.printf("%d: y1 %d", pos, cmd.Value)
- err := m.movedown(cmd.Value)
- if err != nil {
- return fmt.Errorf("could not y1(%d): %w", cmd.Value, err)
- }
- case opY2:
- cmd := op.cmd().(*CmdY2)
- cmd.read(p.r)
- cur := m.state.cur()
- cur.y = cmd.Value
- cur.vv = m.outVMove(cmd.Value)
- m.flushText()
- m.printf("%d: y2 %d", pos, cmd.Value)
- err := m.movedown(cmd.Value)
- if err != nil {
- return fmt.Errorf("could not y2(%d): %w", cmd.Value, err)
- }
- case opY3:
- cmd := op.cmd().(*CmdY3)
- cmd.read(p.r)
- cur := m.state.cur()
- cur.y = cmd.Value
- cur.vv = m.outVMove(cmd.Value)
- m.flushText()
- m.printf("%d: y3 %d", pos, cmd.Value)
- err := m.movedown(cmd.Value)
- if err != nil {
- return fmt.Errorf("could not y3(%d): %w", cmd.Value, err)
- }
- case opY4:
- cmd := op.cmd().(*CmdY4)
- cmd.read(p.r)
- cur := m.state.cur()
- cur.y = cmd.Value
- cur.vv = m.outVMove(cmd.Value)
- m.flushText()
- m.printf("%d: y4 %d", pos, cmd.Value)
- err := m.movedown(cmd.Value)
- if err != nil {
- return fmt.Errorf("could not y4(%d): %w", cmd.Value, err)
- }
- case opZ0:
- cmd := op.cmd().(*CmdZ0)
- cmd.read(p.r)
- cur := m.state.cur()
- cur.vv = m.outVMove(cur.z)
- m.flushText()
- m.printf("%d: z0 %d", pos, cur.z)
- err := m.movedown(cur.z)
- if err != nil {
- return fmt.Errorf("could not z0(%d): %w", cur.z, err)
- }
- case opZ1:
- cmd := op.cmd().(*CmdZ1)
- cmd.read(p.r)
- cur := m.state.cur()
- cur.z = cmd.Value
- cur.vv = m.outVMove(cmd.Value)
- m.flushText()
- m.printf("%d: z1 %d", pos, cmd.Value)
- err := m.movedown(cmd.Value)
- if err != nil {
- return fmt.Errorf("could not z1(%d): %w", cmd.Value, err)
- }
- case opZ2:
- cmd := op.cmd().(*CmdZ2)
- cmd.read(p.r)
- cur := m.state.cur()
- cur.z = cmd.Value
- cur.vv = m.outVMove(cmd.Value)
- m.flushText()
- m.printf("%d: z2 %d", pos, cmd.Value)
- err := m.movedown(cmd.Value)
- if err != nil {
- return fmt.Errorf("could not z2(%d): %w", cmd.Value, err)
- }
- case opZ3:
- cmd := op.cmd().(*CmdZ3)
- cmd.read(p.r)
- cur := m.state.cur()
- cur.z = cmd.Value
- cur.vv = m.outVMove(cmd.Value)
- m.flushText()
- m.printf("%d: z3 %d", pos, cmd.Value)
- err := m.movedown(cmd.Value)
- if err != nil {
- return fmt.Errorf("could not z3(%d): %w", cmd.Value, err)
- }
- case opZ4:
- cmd := op.cmd().(*CmdZ4)
- cmd.read(p.r)
- cur := m.state.cur()
- cur.z = cmd.Value
- cur.vv = m.outVMove(cmd.Value)
- m.flushText()
- m.printf("%d: z4 %d", pos, cmd.Value)
- err := m.movedown(cmd.Value)
- if err != nil {
- return fmt.Errorf("could not z4(%d): %w", cmd.Value, err)
- }
- case opFntNum00, opFntNum01, opFntNum02, opFntNum03, opFntNum04,
- opFntNum05, opFntNum06, opFntNum07, opFntNum08, opFntNum09,
- opFntNum10, opFntNum11, opFntNum12, opFntNum13, opFntNum14,
- opFntNum15, opFntNum16, opFntNum17, opFntNum18, opFntNum19,
- opFntNum20, opFntNum21, opFntNum22, opFntNum23, opFntNum24,
- opFntNum25, opFntNum26, opFntNum27, opFntNum28, opFntNum29,
- opFntNum30, opFntNum31, opFntNum32, opFntNum33, opFntNum34,
- opFntNum35, opFntNum36, opFntNum37, opFntNum38, opFntNum39,
- opFntNum40, opFntNum41, opFntNum42, opFntNum43, opFntNum44,
- opFntNum45, opFntNum46, opFntNum47, opFntNum48, opFntNum49,
- opFntNum50, opFntNum51, opFntNum52, opFntNum53, opFntNum54,
- opFntNum55, opFntNum56, opFntNum57, opFntNum58, opFntNum59,
- opFntNum60, opFntNum61, opFntNum62, opFntNum63:
- cmd := op.cmd().(*CmdFntNum)
- cmd.read(p.r)
- m.state.f = int(cmd.ID)
- m.flushText()
- m.printf(
- "%d: fntnum%d current font is %s",
- pos, cmd.ID, m.state.fonts[m.state.f].Name,
- )
- case opFnt1:
- cmd := op.cmd().(*CmdFnt1)
- cmd.read(p.r)
- m.state.f = int(cmd.ID)
- m.flushText()
- m.printf(
- "%d: fnt1 %d current font is %s",
- pos, cmd.ID, m.state.fonts[m.state.f].Name,
- )
- case opFnt2:
- cmd := op.cmd().(*CmdFnt2)
- cmd.read(p.r)
- m.state.f = int(cmd.ID)
- m.flushText()
- m.printf(
- "%d: fnt2 %d current font is %s",
- pos, cmd.ID, m.state.fonts[m.state.f].Name,
- )
- case opFnt3:
- cmd := op.cmd().(*CmdFnt3)
- cmd.read(p.r)
- m.state.f = int(cmd.ID)
- m.flushText()
- m.printf(
- "%d: fnt3 %d current font is %s",
- pos, cmd.ID, m.state.fonts[m.state.f].Name,
- )
- case opFnt4:
- cmd := op.cmd().(*CmdFnt4)
- cmd.read(p.r)
- m.state.f = int(cmd.ID)
- m.flushText()
- m.printf(
- "%d: fnt4 %d current font is %s",
- pos, cmd.ID, m.state.fonts[m.state.f].Name,
- )
- case opXXX1:
- cmd := op.cmd().(*CmdXXX1)
- cmd.read(p.r)
- m.flushText()
- m.printf("%d: xxx '%s'", pos, cmd.Value)
- err := m.handleSpecial(cmd.Value)
- if err != nil {
- return fmt.Errorf("could not xxx1 %q: %w", cmd.Value, err)
- }
- case opXXX2:
- cmd := op.cmd().(*CmdXXX2)
- cmd.read(p.r)
- m.flushText()
- m.printf("%d: xxx '%s'", pos, cmd.Value)
- err := m.handleSpecial(cmd.Value)
- if err != nil {
- return fmt.Errorf("could not xxx2 %q: %w", cmd.Value, err)
- }
- case opXXX3:
- cmd := op.cmd().(*CmdXXX3)
- cmd.read(p.r)
- m.flushText()
- m.printf("%d: xxx '%s'", pos, cmd.Value)
- err := m.handleSpecial(cmd.Value)
- if err != nil {
- return fmt.Errorf("could not xxx3 %q: %w", cmd.Value, err)
- }
- case opXXX4:
- cmd := op.cmd().(*CmdXXX4)
- cmd.read(p.r)
- m.flushText()
- m.printf("%d: xxx '%s'", pos, cmd.Value)
- err := m.handleSpecial(cmd.Value)
- if err != nil {
- return fmt.Errorf("could not xxx4 %q: %w", cmd.Value, err)
- }
- case opFntDef1:
- cmd := op.cmd().(*CmdFntDef1)
- cmd.read(p.r)
- m.flushText()
- m.printf("%d: fntdef1 %d: %s", pos, cmd.ID, cmd.Font)
- err := m.defineFont(int(cmd.ID), fntdef{
- ID: int(cmd.ID),
- Checksum: cmd.Checksum,
- Size: cmd.Size,
- Design: cmd.Design,
- Area: cmd.Area,
- Name: cmd.Font,
- })
- if err != nil {
- return fmt.Errorf("could not fntdef1 %d: %w", cmd.ID, err)
- }
- case opFntDef2:
- cmd := op.cmd().(*CmdFntDef2)
- cmd.read(p.r)
- m.flushText()
- m.printf("%d: fntdef2 %d: %s", pos, cmd.ID, cmd.Font)
- err := m.defineFont(int(cmd.ID), fntdef{
- ID: int(cmd.ID),
- Checksum: cmd.Checksum,
- Size: cmd.Size,
- Design: cmd.Design,
- Area: cmd.Area,
- Name: cmd.Font,
- })
- if err != nil {
- return fmt.Errorf("could not fntdef2 %d: %w", cmd.ID, err)
- }
- case opFntDef3:
- cmd := op.cmd().(*CmdFntDef3)
- cmd.read(p.r)
- m.flushText()
- m.printf("%d: fntdef3 %d: %s", pos, cmd.ID, cmd.Font)
- err := m.defineFont(int(cmd.ID), fntdef{
- ID: int(cmd.ID),
- Checksum: cmd.Checksum,
- Size: cmd.Size,
- Design: cmd.Design,
- Area: cmd.Area,
- Name: cmd.Font,
- })
- if err != nil {
- return fmt.Errorf("could not fntdef3 %d: %w", cmd.ID, err)
- }
- case opFntDef4:
- cmd := op.cmd().(*CmdFntDef4)
- cmd.read(p.r)
- m.flushText()
- m.printf("%d: fntdef4 %d: %s", pos, cmd.ID, cmd.Font)
- err := m.defineFont(int(cmd.ID), fntdef{
- ID: int(cmd.ID),
- Checksum: cmd.Checksum,
- Size: cmd.Size,
- Design: cmd.Design,
- Area: cmd.Area,
- Name: cmd.Font,
- })
- if err != nil {
- return fmt.Errorf("could not fntdef4 %d: %w", cmd.ID, err)
- }
- default:
- cmd := op.cmd()
- cmd.read(p.r)
- panic(fmt.Errorf("invalid dvi command %q (op=%d)", op.cmd().Name(), op))
- }
- m.printf(" \n")
- }
- if !eop {
- return errNoEOP
- }
- return nil
- }
- // drawGlyph finishes a command that either sets or puts a character.
- func (m *Machine) drawGlyph(op opCode, cmd int32) error {
- cur := m.state.cur()
- fnt, err := m.loadFont(m.state.f)
- if err != nil {
- return err
- }
- m.rdr.DrawGlyph(cur.h, cur.v, *fnt, cmd, m.color.Color())
- adv, ok := fnt.advance(cmd)
- if !ok {
- return fmt.Errorf("dvi: font %q has no glyph %c", fnt.name, cmd)
- }
- if op >= opPut1 {
- return nil
- }
- cur.hh += m.pixels(int32(adv))
- return m.moveright(int32(adv))
- }
- // drawRule finishes a command that either sets or puts a rule.
- func (m *Machine) drawRule(op opCode, height, width int32) error {
- m.printf(" height %d, width %d", height, width)
- switch {
- case height <= 0 || width <= 0:
- m.printf(" (invisible) ")
- default:
- m.printf(" (%dx%d pixels)", m.rulepixels(height), m.rulepixels(width))
- }
- cur := m.state.cur()
- m.rdr.DrawRule(cur.h, cur.v, width, height, m.color.Color())
- if op == opPutRule {
- return nil
- }
- cur.hh += m.rulepixels(width)
- m.printf(" \n")
- return m.moveright(width)
- }
- // moveright finishes a command that sets h += q.
- func (m *Machine) moveright(q int32) error {
- cur := m.state.cur()
- old := cur.h
- hhh := m.pixels(cur.h + q)
- if absI32(hhh-cur.hh) > maxdrift {
- switch {
- case hhh > cur.hh:
- cur.hh = hhh - maxdrift
- default:
- cur.hh = hhh + maxdrift
- }
- }
- cur.h += q
- m.printf(" h:=%d%+d=%d, hh:=%d", old, q, cur.h, cur.hh)
- return nil
- }
- // movedown finishes a command that sets v += q.
- func (m *Machine) movedown(q int32) error {
- cur := m.state.cur()
- old := cur.v
- vvv := m.pixels(cur.v + q)
- if absI32(vvv-cur.vv) > maxdrift {
- switch {
- case vvv > cur.vv:
- cur.vv = vvv - maxdrift
- default:
- cur.vv = vvv + maxdrift
- }
- }
- cur.v += q
- m.printf(" v:=%d%+d=%d, vv:=%d", old, q, cur.v, cur.vv)
- return nil
- }
- func roundF32(v float32) int32 {
- if v > 0 {
- return int32(v + 0.5)
- }
- return int32(v - 0.5)
- }
- func absI32(v int32) int32 {
- if v < 0 {
- return -v
- }
- return v
- }
- func (m *Machine) pixels(v int32) int32 {
- x := m.conv * float32(v)
- return roundF32(x)
- }
- func (m *Machine) rulepixels(v int32) int32 {
- x := int32(m.conv * float32(v))
- if float32(x) < m.conv*float32(v) {
- return x + 1
- }
- return x
- }
- func (m *Machine) defineFont(i int, def fntdef) error {
- var (
- scale = def.Size
- design = def.Design
- mag int32
- )
- switch {
- case scale <= 0 || design <= 0:
- mag = 1000
- default:
- mag = roundF32((1000 * m.conv * float32(scale)) / (m.trueConv * float32(design)))
- }
- design = roundF32((100 * m.conv * float32(scale)) / (m.trueConv * float32(design)))
- def.mag = mag
- def.Size = scale
- m.state.fonts[i] = def
- _, err := m.loadFont(i)
- if err != nil {
- return fmt.Errorf("could not load font %q: %w", def.Name, err)
- }
- return nil
- }
- func (m *Machine) loadFont(i int) (*Font, error) {
- def := m.state.fonts[i]
- if def.font != nil {
- return def.font, nil
- }
- // FIXME: add support for non-TFM fonts?
- name, err := m.ktx.Find(def.Name + ".tfm")
- if err != nil {
- return nil, fmt.Errorf("could not find TFM font %q: %w", def.Name, err)
- }
- f, err := m.ktx.Open(name)
- if err != nil {
- return nil, fmt.Errorf("could not open TFM font %q: %w", def.Name, err)
- }
- defer f.Close()
- font, err := tfm.Parse(f)
- if err != nil {
- return nil, fmt.Errorf("could not parse TFM font %q: %w", def.Name, err)
- }
- def.font = &Font{
- name: def.Name,
- font: font,
- scale: fixed.Int12_20(def.Size),
- }
- m.state.fonts[i] = def
- return def.font, nil
- }
- func (m *Machine) font(i int) *Font {
- fnt, err := m.loadFont(i)
- if err != nil {
- panic(err)
- }
- return fnt
- }
- func (m *Machine) outText(c uint8) {
- if len(m.buf) == cap(m.buf) {
- m.printf("[%s]\n", m.buf)
- m.buf = m.buf[:0]
- }
- m.buf = append(m.buf, c)
- }
- func (m *Machine) flushText() {
- if len(m.buf) == 0 {
- return
- }
- m.printf("[%s]\n", m.buf)
- m.buf = m.buf[:0]
- }
- func (m *Machine) outSpace(v int32) int32 {
- def := m.state.fonts[m.state.f]
- space := def.Size / 6 // this is a 3-unit "thin space"
- cur := m.state.cur()
- switch {
- case v >= space || v <= -4*space:
- m.outText(' ')
- cur.hh = m.pixels(cur.h + v)
- default:
- cur.hh += m.pixels(v)
- }
- return cur.hh
- }
- func (m *Machine) outVMove(v int32) int32 {
- def := m.state.fonts[m.state.f]
- space := def.Size / 6 // this is a 3-unit "thin space"
- cur := m.state.cur()
- switch {
- case absI32(v) >= 5*space:
- cur.vv = m.pixels(cur.v + v)
- default:
- cur.vv += m.pixels(v)
- }
- return cur.vv
- }
- func (m *Machine) handleSpecial(p []byte) error {
- for _, h := range m.handlers {
- err := h.Handle(p)
- if err == nil || !errors.Is(err, ErrSkipHandler) {
- return err
- }
- }
- return nil
- }
- func (m *Machine) printf(format string, args ...interface{}) {
- fmt.Fprintf(m.w, format, args...)
- }
|