Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(47)

Side by Side Diff: freetype/truetype/hint.go

Issue 14930050: code review 14930050: freetype/truetype: implement SPVTL, SFVTL, SHZ, SHPIX o... (Closed)
Patch Set: diff -r 0bd12cbef314 https://code.google.com/p/freetype-go Created 11 years, 5 months ago
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | freetype/truetype/hint_test.go » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2012 The Freetype-Go Authors. All rights reserved. 1 // Copyright 2012 The Freetype-Go Authors. All rights reserved.
2 // Use of this source code is governed by your choice of either the 2 // Use of this source code is governed by your choice of either the
3 // FreeType License or the GNU General Public License version 2 (or 3 // FreeType License or the GNU General Public License version 2 (or
4 // any later version), both of which can be found in the LICENSE file. 4 // any later version), both of which can be found in the LICENSE file.
5 5
6 package truetype 6 package truetype
7 7
8 // This file implements a Truetype bytecode interpreter. 8 // This file implements a Truetype bytecode interpreter.
9 // The opcodes are described at https://developer.apple.com/fonts/TTRefMan/RM05/ Chap5.html 9 // The opcodes are described at https://developer.apple.com/fonts/TTRefMan/RM05/ Chap5.html
10 10
11 import ( 11 import (
12 "errors" 12 "errors"
13 "math"
13 ) 14 )
14 15
15 const ( 16 const (
16 twilightZone = 0 17 twilightZone = 0
17 glyphZone = 1 18 glyphZone = 1
18 numZone = 2 19 numZone = 2
19 ) 20 )
20 21
21 type pointType uint32 22 type pointType uint32
22 23
(...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after
139 } 140 }
140 if len(f.fpgm) != 0 { 141 if len(f.fpgm) != 0 {
141 if err := h.run(f.fpgm, nil, nil, nil, nil); err != nil { 142 if err := h.run(f.fpgm, nil, nil, nil, nil); err != nil {
142 return err 143 return err
143 } 144 }
144 } 145 }
145 } 146 }
146 147
147 if rescale { 148 if rescale {
148 h.scale = scale 149 h.scale = scale
150 h.scaledCVTInitialized = false
149 151
150 h.defaultGS = globalDefaultGS 152 h.defaultGS = globalDefaultGS
151 153
152 if len(f.prep) != 0 { 154 if len(f.prep) != 0 {
153 if err := h.run(f.prep, nil, nil, nil, nil); err != nil { 155 if err := h.run(f.prep, nil, nil, nil, nil); err != nil {
154 return err 156 return err
155 } 157 }
156 h.defaultGS = h.gs 158 h.defaultGS = h.gs
157 // The MS rasterizer doesn't allow the following graphic s state 159 // The MS rasterizer doesn't allow the following graphic s state
158 // variables to be modified by the CVT program. 160 // variables to be modified by the CVT program.
159 h.defaultGS.pv = globalDefaultGS.pv 161 h.defaultGS.pv = globalDefaultGS.pv
160 h.defaultGS.fv = globalDefaultGS.fv 162 h.defaultGS.fv = globalDefaultGS.fv
161 h.defaultGS.dv = globalDefaultGS.dv 163 h.defaultGS.dv = globalDefaultGS.dv
162 h.defaultGS.rp = globalDefaultGS.rp 164 h.defaultGS.rp = globalDefaultGS.rp
163 h.defaultGS.zp = globalDefaultGS.zp 165 h.defaultGS.zp = globalDefaultGS.zp
164 h.defaultGS.loop = globalDefaultGS.loop 166 h.defaultGS.loop = globalDefaultGS.loop
165 } 167 }
166 } 168 }
167 return nil 169 return nil
168 } 170 }
169 171
170 func (h *Hinter) run(program []byte, pCurrent, pUnhinted, pInFontUnits []Point, ends []int) error { 172 func (h *Hinter) run(program []byte, pCurrent, pUnhinted, pInFontUnits []Point, ends []int) error {
171 h.gs = h.defaultGS 173 h.gs = h.defaultGS
172 h.points[glyphZone][current] = pCurrent 174 h.points[glyphZone][current] = pCurrent
173 h.points[glyphZone][unhinted] = pUnhinted 175 h.points[glyphZone][unhinted] = pUnhinted
174 h.points[glyphZone][inFontUnits] = pInFontUnits 176 h.points[glyphZone][inFontUnits] = pInFontUnits
175 h.ends = ends 177 h.ends = ends
176 h.scaledCVTInitialized = false
177 178
178 if len(program) > 50000 { 179 if len(program) > 50000 {
179 return errors.New("truetype: hinting: too many instructions") 180 return errors.New("truetype: hinting: too many instructions")
180 } 181 }
181 var ( 182 var (
182 steps, pc, top int 183 steps, pc, top int
183 opcode uint8 184 opcode uint8
184 185
185 callStack [32]callStackEntry 186 callStack [32]callStackEntry
186 callStackTop int 187 callStackTop int
(...skipping 30 matching lines...) Expand all
217 case opSPVTCA1: 218 case opSPVTCA1:
218 h.gs.pv = [2]f2dot14{0x4000, 0} 219 h.gs.pv = [2]f2dot14{0x4000, 0}
219 h.gs.dv = [2]f2dot14{0x4000, 0} 220 h.gs.dv = [2]f2dot14{0x4000, 0}
220 221
221 case opSFVTCA0: 222 case opSFVTCA0:
222 h.gs.fv = [2]f2dot14{0, 0x4000} 223 h.gs.fv = [2]f2dot14{0, 0x4000}
223 224
224 case opSFVTCA1: 225 case opSFVTCA1:
225 h.gs.fv = [2]f2dot14{0x4000, 0} 226 h.gs.fv = [2]f2dot14{0x4000, 0}
226 227
228 case opSPVTL0, opSPVTL1, opSFVTL0, opSFVTL1:
229 top -= 2
230 p1 := h.point(0, current, h.stack[top+0])
231 p2 := h.point(0, current, h.stack[top+1])
232 if p1 == nil || p2 == nil {
233 return errors.New("truetype: hinting: point out of range")
234 }
235 dx := f2dot14(p1.X - p2.X)
236 dy := f2dot14(p1.Y - p2.Y)
237 if dx == 0 && dy == 0 {
238 dx = 0x4000
239 } else if opcode&1 != 0 {
240 // Counter-clockwise rotation.
241 dx, dy = -dy, dx
242 }
243 v := normalize(dx, dy)
244 if opcode < opSFVTL0 {
245 h.gs.pv = v
246 h.gs.dv = v
247 } else {
248 h.gs.fv = v
249 }
250
227 case opSPVFS: 251 case opSPVFS:
228 top -= 2 252 top -= 2
229 h.gs.pv[0] = f2dot14(h.stack[top+0]) 253 h.gs.pv[0] = f2dot14(h.stack[top+0])
230 h.gs.pv[1] = f2dot14(h.stack[top+1]) 254 h.gs.pv[1] = f2dot14(h.stack[top+1])
231 // TODO: normalize h.gs.pv ?? 255 // TODO: normalize h.gs.pv ??
232 // TODO: h.gs.dv = h.gs.pv ?? 256 // TODO: h.gs.dv = h.gs.pv ??
233 257
234 case opSFVFS: 258 case opSFVFS:
235 top -= 2 259 top -= 2
236 h.gs.fv[0] = f2dot14(h.stack[top+0]) 260 h.gs.fv[0] = f2dot14(h.stack[top+0])
(...skipping 174 matching lines...) Expand 10 before | Expand all | Expand 10 after
411 p := h.point(0, current, i) 435 p := h.point(0, current, i)
412 if p == nil { 436 if p == nil {
413 return errors.New("truetype: hinting: point out of range") 437 return errors.New("truetype: hinting: point out of range")
414 } 438 }
415 distance := f26dot6(0) 439 distance := f26dot6(0)
416 if opcode == opMDAP1 { 440 if opcode == opMDAP1 {
417 distance = dotProduct(f26dot6(p.X), f26dot6(p.Y) , h.gs.pv) 441 distance = dotProduct(f26dot6(p.X), f26dot6(p.Y) , h.gs.pv)
418 // TODO: metrics compensation. 442 // TODO: metrics compensation.
419 distance = h.round(distance) - distance 443 distance = h.round(distance) - distance
420 } 444 }
421 » » » h.move(p, distance) 445 » » » h.move(p, distance, true)
422 h.gs.rp[0] = i 446 h.gs.rp[0] = i
423 h.gs.rp[1] = i 447 h.gs.rp[1] = i
424 448
425 case opIUP0, opIUP1: 449 case opIUP0, opIUP1:
426 iupY, mask := opcode == opIUP0, uint32(flagTouchedX) 450 iupY, mask := opcode == opIUP0, uint32(flagTouchedX)
427 if iupY { 451 if iupY {
428 mask = flagTouchedY 452 mask = flagTouchedY
429 } 453 }
430 prevEnd := 0 454 prevEnd := 0
431 for _, end := range h.ends { 455 for _, end := range h.ends {
(...skipping 17 matching lines...) Expand all
449 } else { 473 } else {
450 h.iupInterp(iupY, curTouched+1, end-1, curTouched, firstTouched) 474 h.iupInterp(iupY, curTouched+1, end-1, curTouched, firstTouched)
451 if firstTouched > 0 { 475 if firstTouched > 0 {
452 h.iupInterp(iupY, prevEn d, firstTouched-1, curTouched, firstTouched) 476 h.iupInterp(iupY, prevEn d, firstTouched-1, curTouched, firstTouched)
453 } 477 }
454 } 478 }
455 } 479 }
456 prevEnd = end 480 prevEnd = end
457 } 481 }
458 482
483 case opSHZ0, opSHZ1:
484 top--
485 zonePointer, i, d, ok := h.displacement(opcode&1 == 0)
486 if !ok {
487 return errors.New("truetype: hinting: point out of range")
488 }
489
490 // As per C Freetype, SHZ doesn't move the phantom point s, or mark
491 // the points as touched.
492 limit := int32(len(h.points[h.gs.zp[2]][current]))
493 if h.gs.zp[2] == glyphZone {
494 limit -= 4
495 }
496 for j := int32(0); j < limit; j++ {
497 if i != j || h.gs.zp[zonePointer] != h.gs.zp[2] {
498 h.move(h.point(2, current, j), d, false)
499 }
500 }
501
502 case opSHPIX:
503 top--
504 d := f26dot6(h.stack[top])
505 if top < int(h.gs.loop) {
506 return errors.New("truetype: hinting: stack unde rflow")
507 }
508 for ; h.gs.loop != 0; h.gs.loop-- {
509 top--
510 p := h.point(2, current, h.stack[top])
511 if p == nil {
512 return errors.New("truetype: hinting: po int out of range")
513 }
514 h.move(p, d, true)
515 }
516 h.gs.loop = 1
517
459 case opIP: 518 case opIP:
460 if top < int(h.gs.loop) { 519 if top < int(h.gs.loop) {
461 return errors.New("truetype: hinting: stack unde rflow") 520 return errors.New("truetype: hinting: stack unde rflow")
462 } 521 }
463 pointType := inFontUnits 522 pointType := inFontUnits
464 twilight := h.gs.zp[0] == 0 || h.gs.zp[1] == 0 || h.gs.z p[2] == 0 523 twilight := h.gs.zp[0] == 0 || h.gs.zp[1] == 0 || h.gs.z p[2] == 0
465 if twilight { 524 if twilight {
466 pointType = unhinted 525 pointType = unhinted
467 } 526 }
468 p := h.point(1, pointType, h.gs.rp[2]) 527 p := h.point(1, pointType, h.gs.rp[2])
(...skipping 21 matching lines...) Expand all
490 if x < 0 { 549 if x < 0 {
491 x -= int64(oldRange) / 2 550 x -= int64(oldRange) / 2
492 } else { 551 } else {
493 x += int64(oldRange) / 2 552 x += int64(oldRange) / 2
494 } 553 }
495 newDist = f26dot6(x / int64(oldR ange)) 554 newDist = f26dot6(x / int64(oldR ange))
496 } else { 555 } else {
497 newDist = -oldDist 556 newDist = -oldDist
498 } 557 }
499 } 558 }
500 » » » » h.move(p, newDist-curDist) 559 » » » » h.move(p, newDist-curDist, true)
501 } 560 }
502 h.gs.loop = 1 561 h.gs.loop = 1
503 562
504 case opALIGNRP: 563 case opALIGNRP:
505 if top < int(h.gs.loop) { 564 if top < int(h.gs.loop) {
506 return errors.New("truetype: hinting: stack unde rflow") 565 return errors.New("truetype: hinting: stack unde rflow")
507 } 566 }
508 ref := h.point(0, current, h.gs.rp[0]) 567 ref := h.point(0, current, h.gs.rp[0])
509 if ref == nil { 568 if ref == nil {
510 return errors.New("truetype: hinting: point out of range") 569 return errors.New("truetype: hinting: point out of range")
511 } 570 }
512 for ; h.gs.loop != 0; h.gs.loop-- { 571 for ; h.gs.loop != 0; h.gs.loop-- {
513 top-- 572 top--
514 p := h.point(1, current, h.stack[top]) 573 p := h.point(1, current, h.stack[top])
515 if p == nil { 574 if p == nil {
516 return errors.New("truetype: hinting: po int out of range") 575 return errors.New("truetype: hinting: po int out of range")
517 } 576 }
518 » » » » h.move(p, -dotProduct(f26dot6(p.X-ref.X), f26dot 6(p.Y-ref.Y), h.gs.pv)) 577 » » » » h.move(p, -dotProduct(f26dot6(p.X-ref.X), f26dot 6(p.Y-ref.Y), h.gs.pv), true)
519 } 578 }
520 h.gs.loop = 1 579 h.gs.loop = 1
521 580
522 case opRTDG: 581 case opRTDG:
523 h.gs.roundPeriod = 1 << 5 582 h.gs.roundPeriod = 1 << 5
524 h.gs.roundPhase = 0 583 h.gs.roundPhase = 0
525 h.gs.roundThreshold = 1 << 4 584 h.gs.roundThreshold = 1 << 4
526 585
527 case opMIAP0, opMIAP1: 586 case opMIAP0, opMIAP1:
528 top -= 2 587 top -= 2
529 i := h.stack[top] 588 i := h.stack[top]
530 distance := h.getScaledCVT(h.stack[top+1]) 589 distance := h.getScaledCVT(h.stack[top+1])
531 if h.gs.zp[0] == 0 { 590 if h.gs.zp[0] == 0 {
532 p := h.point(0, unhinted, i) 591 p := h.point(0, unhinted, i)
533 q := h.point(0, current, i) 592 q := h.point(0, current, i)
534 p.X = int32((int64(distance) * int64(h.gs.fv[0]) ) >> 14) 593 p.X = int32((int64(distance) * int64(h.gs.fv[0]) ) >> 14)
535 p.Y = int32((int64(distance) * int64(h.gs.fv[1]) ) >> 14) 594 p.Y = int32((int64(distance) * int64(h.gs.fv[1]) ) >> 14)
536 *q = *p 595 *q = *p
537 } 596 }
538 p := h.point(0, current, i) 597 p := h.point(0, current, i)
539 oldDist := dotProduct(f26dot6(p.X), f26dot6(p.Y), h.gs.p v) 598 oldDist := dotProduct(f26dot6(p.X), f26dot6(p.Y), h.gs.p v)
540 if opcode == opMIAP1 { 599 if opcode == opMIAP1 {
541 if (distance - oldDist).abs() > h.gs.controlValu eCutIn { 600 if (distance - oldDist).abs() > h.gs.controlValu eCutIn {
542 distance = oldDist 601 distance = oldDist
543 } 602 }
544 // TODO: metrics compensation. 603 // TODO: metrics compensation.
545 distance = h.round(distance) 604 distance = h.round(distance)
546 } 605 }
547 » » » h.move(p, distance-oldDist) 606 » » » h.move(p, distance-oldDist, true)
548 h.gs.rp[0] = i 607 h.gs.rp[0] = i
549 h.gs.rp[1] = i 608 h.gs.rp[1] = i
550 609
551 case opNPUSHB: 610 case opNPUSHB:
552 opcode = 0 611 opcode = 0
553 goto push 612 goto push
554 613
555 case opNPUSHW: 614 case opNPUSHW:
556 opcode = 0x80 615 opcode = 0x80
557 goto push 616 goto push
(...skipping 309 matching lines...) Expand 10 before | Expand all | Expand 10 after
867 926
868 // Set-RP0 bit. 927 // Set-RP0 bit.
869 if opcode&0x10 != 0 { 928 if opcode&0x10 != 0 {
870 h.gs.rp[0] = i 929 h.gs.rp[0] = i
871 } 930 }
872 h.gs.rp[1] = h.gs.rp[0] 931 h.gs.rp[1] = h.gs.rp[0]
873 h.gs.rp[2] = i 932 h.gs.rp[2] = i
874 933
875 // Move the point. 934 // Move the point.
876 oldDist = dotProduct(f26dot6(p.X-ref.X), f26dot6(p.Y-ref .Y), h.gs.pv) 935 oldDist = dotProduct(f26dot6(p.X-ref.X), f26dot6(p.Y-ref .Y), h.gs.pv)
877 » » » h.move(p, distance-oldDist) 936 » » » h.move(p, distance-oldDist, true)
878 937
879 case opMIRP00000, opMIRP00001, opMIRP00010, opMIRP00011, 938 case opMIRP00000, opMIRP00001, opMIRP00010, opMIRP00011,
880 opMIRP00100, opMIRP00101, opMIRP00110, opMIRP00111, 939 opMIRP00100, opMIRP00101, opMIRP00110, opMIRP00111,
881 opMIRP01000, opMIRP01001, opMIRP01010, opMIRP01011, 940 opMIRP01000, opMIRP01001, opMIRP01010, opMIRP01011,
882 opMIRP01100, opMIRP01101, opMIRP01110, opMIRP01111, 941 opMIRP01100, opMIRP01101, opMIRP01110, opMIRP01111,
883 opMIRP10000, opMIRP10001, opMIRP10010, opMIRP10011, 942 opMIRP10000, opMIRP10001, opMIRP10010, opMIRP10011,
884 opMIRP10100, opMIRP10101, opMIRP10110, opMIRP10111, 943 opMIRP10100, opMIRP10101, opMIRP10110, opMIRP10111,
885 opMIRP11000, opMIRP11001, opMIRP11010, opMIRP11011, 944 opMIRP11000, opMIRP11001, opMIRP11010, opMIRP11011,
886 opMIRP11100, opMIRP11101, opMIRP11110, opMIRP11111: 945 opMIRP11100, opMIRP11101, opMIRP11110, opMIRP11111:
887 946
(...skipping 19 matching lines...) Expand all
907 if ref == nil || p == nil { 966 if ref == nil || p == nil {
908 return errors.New("truetype: hinting: point out of range") 967 return errors.New("truetype: hinting: point out of range")
909 } 968 }
910 oldDist := dotProduct(f26dot6(p.X-ref.X), f26dot6(p.Y-re f.Y), h.gs.dv) 969 oldDist := dotProduct(f26dot6(p.X-ref.X), f26dot6(p.Y-re f.Y), h.gs.dv)
911 970
912 ref = h.point(0, current, h.gs.rp[0]) 971 ref = h.point(0, current, h.gs.rp[0])
913 p = h.point(1, current, i) 972 p = h.point(1, current, i)
914 if ref == nil || p == nil { 973 if ref == nil || p == nil {
915 return errors.New("truetype: hinting: point out of range") 974 return errors.New("truetype: hinting: point out of range")
916 } 975 }
917 » » » curDist := dotProduct(f26dot6(p.X-ref.X), f26dot6(p.Y-re f.Y), h.gs.dv) 976 » » » curDist := dotProduct(f26dot6(p.X-ref.X), f26dot6(p.Y-re f.Y), h.gs.pv)
918 977
919 if h.gs.autoFlip && oldDist^cvtDist < 0 { 978 if h.gs.autoFlip && oldDist^cvtDist < 0 {
920 cvtDist = -cvtDist 979 cvtDist = -cvtDist
921 } 980 }
922 981
923 // Rounding bit. 982 // Rounding bit.
924 // TODO: metrics compensation. 983 // TODO: metrics compensation.
925 » » » distance := oldDist 984 » » » distance := cvtDist
926 if opcode&0x04 != 0 { 985 if opcode&0x04 != 0 {
927 » » » » distance = h.round(oldDist) 986 » » » » distance = h.round(cvtDist)
928 } 987 }
929 988
930 // Minimum distance bit. 989 // Minimum distance bit.
931 if opcode&0x08 != 0 { 990 if opcode&0x08 != 0 {
932 if oldDist >= 0 { 991 if oldDist >= 0 {
933 if distance < h.gs.minDist { 992 if distance < h.gs.minDist {
934 distance = h.gs.minDist 993 distance = h.gs.minDist
935 } 994 }
936 } else { 995 } else {
937 if distance > -h.gs.minDist { 996 if distance > -h.gs.minDist {
938 distance = -h.gs.minDist 997 distance = -h.gs.minDist
939 } 998 }
940 } 999 }
941 } 1000 }
942 1001
943 // Set-RP0 bit. 1002 // Set-RP0 bit.
944 if opcode&0x10 != 0 { 1003 if opcode&0x10 != 0 {
945 h.gs.rp[0] = i 1004 h.gs.rp[0] = i
946 } 1005 }
947 h.gs.rp[1] = h.gs.rp[0] 1006 h.gs.rp[1] = h.gs.rp[0]
948 h.gs.rp[2] = i 1007 h.gs.rp[2] = i
949 1008
950 // Move the point. 1009 // Move the point.
951 » » » h.move(p, distance-curDist) 1010 » » » h.move(p, distance-curDist, true)
952 1011
953 default: 1012 default:
954 return errors.New("truetype: hinting: unrecognized instr uction") 1013 return errors.New("truetype: hinting: unrecognized instr uction")
955 } 1014 }
956 pc++ 1015 pc++
957 continue 1016 continue
958 1017
959 ifelse: 1018 ifelse:
960 // Skip past bytecode until the next ELSE (if opcode == 0) or th e 1019 // Skip past bytecode until the next ELSE (if opcode == 0) or th e
961 // next EIF (for all opcodes). Opcode == 0 means that we have co me 1020 // next EIF (for all opcodes). Opcode == 0 means that we have co me
(...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after
1070 } 1129 }
1071 1130
1072 func (h *Hinter) point(zonePointer uint32, pt pointType, i int32) *Point { 1131 func (h *Hinter) point(zonePointer uint32, pt pointType, i int32) *Point {
1073 points := h.points[h.gs.zp[zonePointer]][pt] 1132 points := h.points[h.gs.zp[zonePointer]][pt]
1074 if i < 0 || len(points) <= int(i) { 1133 if i < 0 || len(points) <= int(i) {
1075 return nil 1134 return nil
1076 } 1135 }
1077 return &points[i] 1136 return &points[i]
1078 } 1137 }
1079 1138
1080 func (h *Hinter) move(p *Point, distance f26dot6) { 1139 func (h *Hinter) move(p *Point, distance f26dot6, touch bool) {
1081 » if h.gs.fv[0] == 0 { 1140 » fvx := int64(h.gs.fv[0])
1082 » » p.Y += int32(distance) 1141 » pvx := int64(h.gs.pv[0])
1083 » » p.Flags |= flagTouchedY 1142 » if fvx == 0x4000 && pvx == 0x4000 {
1143 » » p.X += int32(distance)
1144 » » if touch {
1145 » » » p.Flags |= flagTouchedX
1146 » » }
1084 return 1147 return
1085 } 1148 }
1086 » if h.gs.fv[1] == 0 { 1149
1087 » » p.X += int32(distance) 1150 » fvy := int64(h.gs.fv[1])
1088 » » p.Flags |= flagTouchedX 1151 » pvy := int64(h.gs.pv[1])
1152 » if fvy == 0x4000 && pvy == 0x4000 {
1153 » » p.Y += int32(distance)
1154 » » if touch {
1155 » » » p.Flags |= flagTouchedY
1156 » » }
1089 return 1157 return
1090 } 1158 }
1091 » fvx := int64(h.gs.fv[0]) 1159
1092 » fvy := int64(h.gs.fv[1])
1093 » pvx := int64(h.gs.pv[0])
1094 » pvy := int64(h.gs.pv[1])
1095 fvDotPv := (fvx*pvx + fvy*pvy) >> 14 1160 fvDotPv := (fvx*pvx + fvy*pvy) >> 14
1096 » p.X += int32(int64(distance) * fvx / fvDotPv) 1161
1097 » p.Y += int32(int64(distance) * fvy / fvDotPv) 1162 » if fvx != 0 {
1098 » p.Flags |= flagTouchedX | flagTouchedY 1163 » » numer, denom := fvx*int64(distance), fvDotPv
1164 » » if denom < 0 {
bsiegert 2013/10/23 11:43:32 How about a helper function for the rounding?
1165 » » » numer, denom = -numer, -denom
1166 » » }
1167 » » if numer >= 0 {
1168 » » » numer += denom / 2
1169 » » } else {
1170 » » » numer -= denom / 2
1171 » » }
1172 » » p.X += int32(numer / denom)
1173 » » if touch {
1174 » » » p.Flags |= flagTouchedX
1175 » » }
1176 » }
1177
1178 » if fvy != 0 {
1179 » » numer, denom := fvy*int64(distance), fvDotPv
1180 » » if denom < 0 {
1181 » » » numer, denom = -numer, -denom
1182 » » }
1183 » » if numer >= 0 {
1184 » » » numer += denom / 2
1185 » » } else {
1186 » » » numer -= denom / 2
1187 » » }
1188 » » p.Y += int32(numer / denom)
1189 » » if touch {
1190 » » » p.Flags |= flagTouchedY
1191 » » }
1192 » }
1099 } 1193 }
1100 1194
1101 func (h *Hinter) iupInterp(interpY bool, p1, p2, ref1, ref2 int) { 1195 func (h *Hinter) iupInterp(interpY bool, p1, p2, ref1, ref2 int) {
1102 if p1 > p2 { 1196 if p1 > p2 {
1103 return 1197 return
1104 } 1198 }
1105 if ref1 >= len(h.points[glyphZone][current]) || 1199 if ref1 >= len(h.points[glyphZone][current]) ||
1106 ref2 >= len(h.points[glyphZone][current]) { 1200 ref2 >= len(h.points[glyphZone][current]) {
1107 return 1201 return
1108 } 1202 }
(...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after
1215 continue 1309 continue
1216 } 1310 }
1217 if interpY { 1311 if interpY {
1218 h.points[glyphZone][current][i].Y += delta 1312 h.points[glyphZone][current][i].Y += delta
1219 } else { 1313 } else {
1220 h.points[glyphZone][current][i].X += delta 1314 h.points[glyphZone][current][i].X += delta
1221 } 1315 }
1222 } 1316 }
1223 } 1317 }
1224 1318
1319 func (h *Hinter) displacement(useZP1 bool) (zonePointer uint32, i int32, d f26do t6, ok bool) {
1320 zonePointer, i = uint32(0), h.gs.rp[1]
1321 if useZP1 {
1322 zonePointer, i = 1, h.gs.rp[2]
1323 }
1324 p := h.point(zonePointer, current, i)
1325 q := h.point(zonePointer, unhinted, i)
1326 if p == nil || q == nil {
1327 return 0, 0, 0, false
1328 }
1329 d = dotProduct(f26dot6(p.X-q.X), f26dot6(p.Y-q.Y), h.gs.pv)
1330 return zonePointer, i, d, true
1331 }
1332
1225 // skipInstructionPayload increments pc by the extra data that follows a 1333 // skipInstructionPayload increments pc by the extra data that follows a
1226 // variable length PUSHB or PUSHW instruction. 1334 // variable length PUSHB or PUSHW instruction.
1227 func skipInstructionPayload(program []byte, pc int) (newPC int, ok bool) { 1335 func skipInstructionPayload(program []byte, pc int) (newPC int, ok bool) {
1228 switch program[pc] { 1336 switch program[pc] {
1229 case opNPUSHB: 1337 case opNPUSHB:
1230 pc++ 1338 pc++
1231 if pc >= len(program) { 1339 if pc >= len(program) {
1232 return 0, false 1340 return 0, false
1233 } 1341 }
1234 pc += int(program[pc]) 1342 pc += int(program[pc])
1235 case opNPUSHW: 1343 case opNPUSHW:
1236 pc++ 1344 pc++
1237 if pc >= len(program) { 1345 if pc >= len(program) {
1238 return 0, false 1346 return 0, false
1239 } 1347 }
1240 pc += 2 * int(program[pc]) 1348 pc += 2 * int(program[pc])
1241 case opPUSHB000, opPUSHB001, opPUSHB010, opPUSHB011, 1349 case opPUSHB000, opPUSHB001, opPUSHB010, opPUSHB011,
1242 opPUSHB100, opPUSHB101, opPUSHB110, opPUSHB111: 1350 opPUSHB100, opPUSHB101, opPUSHB110, opPUSHB111:
1243 pc += int(program[pc] - (opPUSHB000 - 1)) 1351 pc += int(program[pc] - (opPUSHB000 - 1))
1244 case opPUSHW000, opPUSHW001, opPUSHW010, opPUSHW011, 1352 case opPUSHW000, opPUSHW001, opPUSHW010, opPUSHW011,
1245 opPUSHW100, opPUSHW101, opPUSHW110, opPUSHW111: 1353 opPUSHW100, opPUSHW101, opPUSHW110, opPUSHW111:
1246 pc += 2 * int(program[pc]-(opPUSHW000-1)) 1354 pc += 2 * int(program[pc]-(opPUSHW000-1))
1247 } 1355 }
1248 return pc, true 1356 return pc, true
1249 } 1357 }
1250 1358
1251 // f2dot14 is a 2.14 fixed point number. 1359 // f2dot14 is a 2.14 fixed point number.
1252 type f2dot14 int16 1360 type f2dot14 int16
1253 1361
1362 func normalize(x, y f2dot14) [2]f2dot14 {
1363 fx, fy := float64(x), float64(y)
1364 l := math.Sqrt(fx*fx + fy*fy)
bsiegert 2013/10/23 11:43:32 math.Hypot(fx, fy)
1365 fx /= l
1366 fy /= l
1367 return [2]f2dot14{
1368 f2dot14(fx * 0x4000),
1369 f2dot14(fy * 0x4000),
1370 }
1371 }
1372
1254 // f26dot6 is a 26.6 fixed point number. 1373 // f26dot6 is a 26.6 fixed point number.
1255 type f26dot6 int32 1374 type f26dot6 int32
1256 1375
1257 // abs returns abs(x) in 26.6 fixed point arithmetic. 1376 // abs returns abs(x) in 26.6 fixed point arithmetic.
1258 func (x f26dot6) abs() f26dot6 { 1377 func (x f26dot6) abs() f26dot6 {
1259 if x < 0 { 1378 if x < 0 {
1260 return -x 1379 return -x
1261 } 1380 }
1262 return x 1381 return x
1263 } 1382 }
1264 1383
1265 // div returns x/y in 26.6 fixed point arithmetic. 1384 // div returns x/y in 26.6 fixed point arithmetic.
1266 func (x f26dot6) div(y f26dot6) f26dot6 { 1385 func (x f26dot6) div(y f26dot6) f26dot6 {
1267 return f26dot6((int64(x) << 6) / int64(y)) 1386 return f26dot6((int64(x) << 6) / int64(y))
1268 } 1387 }
1269 1388
1270 // mul returns x*y in 26.6 fixed point arithmetic. 1389 // mul returns x*y in 26.6 fixed point arithmetic.
1271 func (x f26dot6) mul(y f26dot6) f26dot6 { 1390 func (x f26dot6) mul(y f26dot6) f26dot6 {
1272 return f26dot6(int64(x) * int64(y) >> 6) 1391 return f26dot6(int64(x) * int64(y) >> 6)
1273 } 1392 }
1274 1393
1275 func dotProduct(x, y f26dot6, q [2]f2dot14) f26dot6 { 1394 func dotProduct(x, y f26dot6, q [2]f2dot14) f26dot6 {
1276 px := int64(x) 1395 px := int64(x)
1277 py := int64(y) 1396 py := int64(y)
1278 qx := int64(q[0]) 1397 qx := int64(q[0])
1279 qy := int64(q[1]) 1398 qy := int64(q[1])
1280 » return f26dot6((px*qx + py*qy) >> 14) 1399 » return f26dot6((px*qx + py*qy + 1<<13) >> 14)
1281 } 1400 }
1282 1401
1283 // round rounds the given number. The rounding algorithm is described at 1402 // round rounds the given number. The rounding algorithm is described at
1284 // https://developer.apple.com/fonts/TTRefMan/RM02/Chap2.html#rounding 1403 // https://developer.apple.com/fonts/TTRefMan/RM02/Chap2.html#rounding
1285 func (h *Hinter) round(x f26dot6) f26dot6 { 1404 func (h *Hinter) round(x f26dot6) f26dot6 {
1286 if h.gs.roundPeriod == 0 { 1405 if h.gs.roundPeriod == 0 {
1287 // Rounding is off. 1406 // Rounding is off.
1288 return x 1407 return x
1289 } 1408 }
1290 if x >= 0 { 1409 if x >= 0 {
1291 ret := (x - h.gs.roundPhase + h.gs.roundThreshold) & -h.gs.round Period 1410 ret := (x - h.gs.roundPhase + h.gs.roundThreshold) & -h.gs.round Period
1292 if x != 0 && ret < 0 { 1411 if x != 0 && ret < 0 {
1293 ret = 0 1412 ret = 0
1294 } 1413 }
1295 return ret + h.gs.roundPhase 1414 return ret + h.gs.roundPhase
1296 } 1415 }
1297 ret := -((-x - h.gs.roundPhase + h.gs.roundThreshold) & -h.gs.roundPerio d) 1416 ret := -((-x - h.gs.roundPhase + h.gs.roundThreshold) & -h.gs.roundPerio d)
1298 if ret > 0 { 1417 if ret > 0 {
1299 ret = 0 1418 ret = 0
1300 } 1419 }
1301 return ret - h.gs.roundPhase 1420 return ret - h.gs.roundPhase
1302 } 1421 }
1303 1422
1304 func bool2int32(b bool) int32 { 1423 func bool2int32(b bool) int32 {
1305 if b { 1424 if b {
1306 return 1 1425 return 1
1307 } 1426 }
1308 return 0 1427 return 0
1309 } 1428 }
OLDNEW
« no previous file with comments | « no previous file | freetype/truetype/hint_test.go » ('j') | no next file with comments »

Powered by Google App Engine
RSS Feeds Recent Issues | This issue
This is Rietveld f62528b