...

Source file src/github.com/golang/freetype/truetype/hint_test.go

Documentation: github.com/golang/freetype/truetype

     1  // Copyright 2012 The Freetype-Go Authors. All rights reserved.
     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
     4  // any later version), both of which can be found in the LICENSE file.
     5  
     6  package truetype
     7  
     8  import (
     9  	"reflect"
    10  	"strings"
    11  	"testing"
    12  
    13  	"golang.org/x/image/math/fixed"
    14  )
    15  
    16  func TestBytecode(t *testing.T) {
    17  	testCases := []struct {
    18  		desc   string
    19  		prog   []byte
    20  		want   []int32
    21  		errStr string
    22  	}{
    23  		{
    24  			"underflow",
    25  			[]byte{
    26  				opDUP,
    27  			},
    28  			nil,
    29  			"underflow",
    30  		},
    31  		{
    32  			"infinite loop",
    33  			[]byte{
    34  				opPUSHW000, // [-1]
    35  				0xff,
    36  				0xff,
    37  				opDUP,  // [-1, -1]
    38  				opJMPR, // [-1]
    39  			},
    40  			nil,
    41  			"too many steps",
    42  		},
    43  		{
    44  			"unbalanced if/else",
    45  			[]byte{
    46  				opPUSHB000, // [0]
    47  				0,
    48  				opIF,
    49  			},
    50  			nil,
    51  			"unbalanced",
    52  		},
    53  		{
    54  			"vector set/gets",
    55  			[]byte{
    56  				opSVTCA1,   // []
    57  				opGPV,      // [0x4000, 0]
    58  				opSVTCA0,   // [0x4000, 0]
    59  				opGFV,      // [0x4000, 0, 0, 0x4000]
    60  				opNEG,      // [0x4000, 0, 0, -0x4000]
    61  				opSPVFS,    // [0x4000, 0]
    62  				opSFVTPV,   // [0x4000, 0]
    63  				opPUSHB000, // [0x4000, 0, 1]
    64  				1,
    65  				opGFV,      // [0x4000, 0, 1, 0, -0x4000]
    66  				opPUSHB000, // [0x4000, 0, 1, 0, -0x4000, 2]
    67  				2,
    68  			},
    69  			[]int32{0x4000, 0, 1, 0, -0x4000, 2},
    70  			"",
    71  		},
    72  		{
    73  			"jumps",
    74  			[]byte{
    75  				opPUSHB001, // [10, 2]
    76  				10,
    77  				2,
    78  				opJMPR,     // [10]
    79  				opDUP,      // not executed
    80  				opDUP,      // [10, 10]
    81  				opPUSHB010, // [10, 10, 20, 2, 1]
    82  				20,
    83  				2,
    84  				1,
    85  				opJROT,     // [10, 10, 20]
    86  				opDUP,      // not executed
    87  				opDUP,      // [10, 10, 20, 20]
    88  				opPUSHB010, // [10, 10, 20, 20, 30, 2, 1]
    89  				30,
    90  				2,
    91  				1,
    92  				opJROF, // [10, 10, 20, 20, 30]
    93  				opDUP,  // [10, 10, 20, 20, 30, 30]
    94  				opDUP,  // [10, 10, 20, 20, 30, 30, 30]
    95  			},
    96  			[]int32{10, 10, 20, 20, 30, 30, 30},
    97  			"",
    98  		},
    99  		{
   100  			"stack ops",
   101  			[]byte{
   102  				opPUSHB010, // [10, 20, 30]
   103  				10,
   104  				20,
   105  				30,
   106  				opCLEAR,    // []
   107  				opPUSHB010, // [40, 50, 60]
   108  				40,
   109  				50,
   110  				60,
   111  				opSWAP,     // [40, 60, 50]
   112  				opDUP,      // [40, 60, 50, 50]
   113  				opDUP,      // [40, 60, 50, 50, 50]
   114  				opPOP,      // [40, 60, 50, 50]
   115  				opDEPTH,    // [40, 60, 50, 50, 4]
   116  				opCINDEX,   // [40, 60, 50, 50, 40]
   117  				opPUSHB000, // [40, 60, 50, 50, 40, 4]
   118  				4,
   119  				opMINDEX, // [40, 50, 50, 40, 60]
   120  			},
   121  			[]int32{40, 50, 50, 40, 60},
   122  			"",
   123  		},
   124  		{
   125  			"push ops",
   126  			[]byte{
   127  				opPUSHB000, // [255]
   128  				255,
   129  				opPUSHW001, // [255, -2, 253]
   130  				255,
   131  				254,
   132  				0,
   133  				253,
   134  				opNPUSHB, // [1, -2, 253, 1, 2]
   135  				2,
   136  				1,
   137  				2,
   138  				opNPUSHW, // [1, -2, 253, 1, 2, 0x0405, 0x0607, 0x0809]
   139  				3,
   140  				4,
   141  				5,
   142  				6,
   143  				7,
   144  				8,
   145  				9,
   146  			},
   147  			[]int32{255, -2, 253, 1, 2, 0x0405, 0x0607, 0x0809},
   148  			"",
   149  		},
   150  		{
   151  			"store ops",
   152  			[]byte{
   153  				opPUSHB011, // [1, 22, 3, 44]
   154  				1,
   155  				22,
   156  				3,
   157  				44,
   158  				opWS,       // [1, 22]
   159  				opWS,       // []
   160  				opPUSHB000, // [3]
   161  				3,
   162  				opRS, // [44]
   163  			},
   164  			[]int32{44},
   165  			"",
   166  		},
   167  		{
   168  			"comparison ops",
   169  			[]byte{
   170  				opPUSHB001, // [10, 20]
   171  				10,
   172  				20,
   173  				opLT,       // [1]
   174  				opPUSHB001, // [1, 10, 20]
   175  				10,
   176  				20,
   177  				opLTEQ,     // [1, 1]
   178  				opPUSHB001, // [1, 1, 10, 20]
   179  				10,
   180  				20,
   181  				opGT,       // [1, 1, 0]
   182  				opPUSHB001, // [1, 1, 0, 10, 20]
   183  				10,
   184  				20,
   185  				opGTEQ, // [1, 1, 0, 0]
   186  				opEQ,   // [1, 1, 1]
   187  				opNEQ,  // [1, 0]
   188  			},
   189  			[]int32{1, 0},
   190  			"",
   191  		},
   192  		{
   193  			"odd/even",
   194  			// Calculate odd(2+31/64), odd(2+32/64), even(2), even(1).
   195  			[]byte{
   196  				opPUSHB000, // [159]
   197  				159,
   198  				opODD,      // [0]
   199  				opPUSHB000, // [0, 160]
   200  				160,
   201  				opODD,      // [0, 1]
   202  				opPUSHB000, // [0, 1, 128]
   203  				128,
   204  				opEVEN,     // [0, 1, 1]
   205  				opPUSHB000, // [0, 1, 1, 64]
   206  				64,
   207  				opEVEN, // [0, 1, 1, 0]
   208  			},
   209  			[]int32{0, 1, 1, 0},
   210  			"",
   211  		},
   212  		{
   213  			"if true",
   214  			[]byte{
   215  				opPUSHB001, // [255, 1]
   216  				255,
   217  				1,
   218  				opIF,
   219  				opPUSHB000, // [255, 2]
   220  				2,
   221  				opEIF,
   222  				opPUSHB000, // [255, 2, 254]
   223  				254,
   224  			},
   225  			[]int32{255, 2, 254},
   226  			"",
   227  		},
   228  		{
   229  			"if false",
   230  			[]byte{
   231  				opPUSHB001, // [255, 0]
   232  				255,
   233  				0,
   234  				opIF,
   235  				opPUSHB000, // [255]
   236  				2,
   237  				opEIF,
   238  				opPUSHB000, // [255, 254]
   239  				254,
   240  			},
   241  			[]int32{255, 254},
   242  			"",
   243  		},
   244  		{
   245  			"if/else true",
   246  			[]byte{
   247  				opPUSHB000, // [1]
   248  				1,
   249  				opIF,
   250  				opPUSHB000, // [2]
   251  				2,
   252  				opELSE,
   253  				opPUSHB000, // not executed
   254  				3,
   255  				opEIF,
   256  			},
   257  			[]int32{2},
   258  			"",
   259  		},
   260  		{
   261  			"if/else false",
   262  			[]byte{
   263  				opPUSHB000, // [0]
   264  				0,
   265  				opIF,
   266  				opPUSHB000, // not executed
   267  				2,
   268  				opELSE,
   269  				opPUSHB000, // [3]
   270  				3,
   271  				opEIF,
   272  			},
   273  			[]int32{3},
   274  			"",
   275  		},
   276  		{
   277  			"if/else true if/else false",
   278  			// 0x58 is the opcode for opIF. The literal 0x58s below are pushed data.
   279  			[]byte{
   280  				opPUSHB010, // [255, 0, 1]
   281  				255,
   282  				0,
   283  				1,
   284  				opIF,
   285  				opIF,
   286  				opPUSHB001, // not executed
   287  				0x58,
   288  				0x58,
   289  				opELSE,
   290  				opPUSHW000, // [255, 0x5858]
   291  				0x58,
   292  				0x58,
   293  				opEIF,
   294  				opELSE,
   295  				opIF,
   296  				opNPUSHB, // not executed
   297  				3,
   298  				0x58,
   299  				0x58,
   300  				0x58,
   301  				opELSE,
   302  				opNPUSHW, // not executed
   303  				2,
   304  				0x58,
   305  				0x58,
   306  				0x58,
   307  				0x58,
   308  				opEIF,
   309  				opEIF,
   310  				opPUSHB000, // [255, 0x5858, 254]
   311  				254,
   312  			},
   313  			[]int32{255, 0x5858, 254},
   314  			"",
   315  		},
   316  		{
   317  			"if/else false if/else true",
   318  			// 0x58 is the opcode for opIF. The literal 0x58s below are pushed data.
   319  			[]byte{
   320  				opPUSHB010, // [255, 1, 0]
   321  				255,
   322  				1,
   323  				0,
   324  				opIF,
   325  				opIF,
   326  				opPUSHB001, // not executed
   327  				0x58,
   328  				0x58,
   329  				opELSE,
   330  				opPUSHW000, // not executed
   331  				0x58,
   332  				0x58,
   333  				opEIF,
   334  				opELSE,
   335  				opIF,
   336  				opNPUSHB, // [255, 0x58, 0x58, 0x58]
   337  				3,
   338  				0x58,
   339  				0x58,
   340  				0x58,
   341  				opELSE,
   342  				opNPUSHW, // not executed
   343  				2,
   344  				0x58,
   345  				0x58,
   346  				0x58,
   347  				0x58,
   348  				opEIF,
   349  				opEIF,
   350  				opPUSHB000, // [255, 0x58, 0x58, 0x58, 254]
   351  				254,
   352  			},
   353  			[]int32{255, 0x58, 0x58, 0x58, 254},
   354  			"",
   355  		},
   356  		{
   357  			"logical ops",
   358  			[]byte{
   359  				opPUSHB010, // [0, 10, 20]
   360  				0,
   361  				10,
   362  				20,
   363  				opAND, // [0, 1]
   364  				opOR,  // [1]
   365  				opNOT, // [0]
   366  			},
   367  			[]int32{0},
   368  			"",
   369  		},
   370  		{
   371  			"arithmetic ops",
   372  			// Calculate abs((-(1 - (2*3)))/2 + 1/64).
   373  			// The answer is 5/2 + 1/64 in ideal numbers, or 161 in 26.6 fixed point math.
   374  			[]byte{
   375  				opPUSHB010, // [64, 128, 192]
   376  				1 << 6,
   377  				2 << 6,
   378  				3 << 6,
   379  				opMUL,      // [64, 384]
   380  				opSUB,      // [-320]
   381  				opNEG,      // [320]
   382  				opPUSHB000, // [320, 128]
   383  				2 << 6,
   384  				opDIV,      // [160]
   385  				opPUSHB000, // [160, 1]
   386  				1,
   387  				opADD, // [161]
   388  				opABS, // [161]
   389  			},
   390  			[]int32{161},
   391  			"",
   392  		},
   393  		{
   394  			"floor, ceiling",
   395  			[]byte{
   396  				opPUSHB000, // [96]
   397  				96,
   398  				opFLOOR,    // [64]
   399  				opPUSHB000, // [64, 96]
   400  				96,
   401  				opCEILING, // [64, 128]
   402  			},
   403  			[]int32{64, 128},
   404  			"",
   405  		},
   406  		{
   407  			"rounding",
   408  			// Round 1.40625 (which is 90/64) under various rounding policies.
   409  			// See figure 20 of https://developer.apple.com/fonts/TTRefMan/RM02/Chap2.html#rounding
   410  			[]byte{
   411  				opROFF,     // []
   412  				opPUSHB000, // [90]
   413  				90,
   414  				opROUND00,  // [90]
   415  				opRTG,      // [90]
   416  				opPUSHB000, // [90, 90]
   417  				90,
   418  				opROUND00,  // [90, 64]
   419  				opRTHG,     // [90, 64]
   420  				opPUSHB000, // [90, 64, 90]
   421  				90,
   422  				opROUND00,  // [90, 64, 96]
   423  				opRDTG,     // [90, 64, 96]
   424  				opPUSHB000, // [90, 64, 96, 90]
   425  				90,
   426  				opROUND00,  // [90, 64, 96, 64]
   427  				opRUTG,     // [90, 64, 96, 64]
   428  				opPUSHB000, // [90, 64, 96, 64, 90]
   429  				90,
   430  				opROUND00,  // [90, 64, 96, 64, 128]
   431  				opRTDG,     // [90, 64, 96, 64, 128]
   432  				opPUSHB000, // [90, 64, 96, 64, 128, 90]
   433  				90,
   434  				opROUND00, // [90, 64, 96, 64, 128, 96]
   435  			},
   436  			[]int32{90, 64, 96, 64, 128, 96},
   437  			"",
   438  		},
   439  		{
   440  			"super-rounding",
   441  			// See figure 20 of https://developer.apple.com/fonts/TTRefMan/RM02/Chap2.html#rounding
   442  			// and the sign preservation steps of the "Order of rounding operations" section.
   443  			[]byte{
   444  				opPUSHB000, // [0x58]
   445  				0x58,
   446  				opSROUND,   // []
   447  				opPUSHW000, // [-81]
   448  				0xff,
   449  				0xaf,
   450  				opROUND00,  // [-80]
   451  				opPUSHW000, // [-80, -80]
   452  				0xff,
   453  				0xb0,
   454  				opROUND00,  // [-80, -80]
   455  				opPUSHW000, // [-80, -80, -17]
   456  				0xff,
   457  				0xef,
   458  				opROUND00,  // [-80, -80, -16]
   459  				opPUSHW000, // [-80, -80, -16, -16]
   460  				0xff,
   461  				0xf0,
   462  				opROUND00,  // [-80, -80, -16, -16]
   463  				opPUSHB000, // [-80, -80, -16, -16, 0]
   464  				0,
   465  				opROUND00,  // [-80, -80, -16, -16, 16]
   466  				opPUSHB000, // [-80, -80, -16, -16, 16, 16]
   467  				16,
   468  				opROUND00,  // [-80, -80, -16, -16, 16, 16]
   469  				opPUSHB000, // [-80, -80, -16, -16, 16, 16, 47]
   470  				47,
   471  				opROUND00,  // [-80, -80, -16, -16, 16, 16, 16]
   472  				opPUSHB000, // [-80, -80, -16, -16, 16, 16, 16, 48]
   473  				48,
   474  				opROUND00, // [-80, -80, -16, -16, 16, 16, 16, 80]
   475  			},
   476  			[]int32{-80, -80, -16, -16, 16, 16, 16, 80},
   477  			"",
   478  		},
   479  		{
   480  			"roll",
   481  			[]byte{
   482  				opPUSHB010, // [1, 2, 3]
   483  				1,
   484  				2,
   485  				3,
   486  				opROLL, // [2, 3, 1]
   487  			},
   488  			[]int32{2, 3, 1},
   489  			"",
   490  		},
   491  		{
   492  			"max/min",
   493  			[]byte{
   494  				opPUSHW001, // [-2, -3]
   495  				0xff,
   496  				0xfe,
   497  				0xff,
   498  				0xfd,
   499  				opMAX,      // [-2]
   500  				opPUSHW001, // [-2, -4, -5]
   501  				0xff,
   502  				0xfc,
   503  				0xff,
   504  				0xfb,
   505  				opMIN, // [-2, -5]
   506  			},
   507  			[]int32{-2, -5},
   508  			"",
   509  		},
   510  		{
   511  			"functions",
   512  			[]byte{
   513  				opPUSHB011, // [3, 7, 0, 3]
   514  				3,
   515  				7,
   516  				0,
   517  				3,
   518  
   519  				opFDEF, // Function #3 (not called)
   520  				opPUSHB000,
   521  				98,
   522  				opENDF,
   523  
   524  				opFDEF, // Function #0
   525  				opDUP,
   526  				opADD,
   527  				opENDF,
   528  
   529  				opFDEF, // Function #7
   530  				opPUSHB001,
   531  				10,
   532  				0,
   533  				opCALL,
   534  				opDUP,
   535  				opENDF,
   536  
   537  				opFDEF, // Function #3 (again)
   538  				opPUSHB000,
   539  				99,
   540  				opENDF,
   541  
   542  				opPUSHB001, // [2, 0]
   543  				2,
   544  				0,
   545  				opCALL,     // [4]
   546  				opPUSHB000, // [4, 3]
   547  				3,
   548  				opLOOPCALL, // [99, 99, 99, 99]
   549  				opPUSHB000, // [99, 99, 99, 99, 7]
   550  				7,
   551  				opCALL, // [99, 99, 99, 99, 20, 20]
   552  			},
   553  			[]int32{99, 99, 99, 99, 20, 20},
   554  			"",
   555  		},
   556  	}
   557  
   558  	for _, tc := range testCases {
   559  		h := &hinter{}
   560  		h.init(&Font{
   561  			maxStorage:       32,
   562  			maxStackElements: 100,
   563  		}, 768)
   564  		err, errStr := h.run(tc.prog, nil, nil, nil, nil), ""
   565  		if err != nil {
   566  			errStr = err.Error()
   567  		}
   568  		if tc.errStr != "" {
   569  			if errStr == "" {
   570  				t.Errorf("%s: got no error, want %q", tc.desc, tc.errStr)
   571  			} else if !strings.Contains(errStr, tc.errStr) {
   572  				t.Errorf("%s: got error %q, want one containing %q", tc.desc, errStr, tc.errStr)
   573  			}
   574  			continue
   575  		}
   576  		if errStr != "" {
   577  			t.Errorf("%s: got error %q, want none", tc.desc, errStr)
   578  			continue
   579  		}
   580  		got := h.stack[:len(tc.want)]
   581  		if !reflect.DeepEqual(got, tc.want) {
   582  			t.Errorf("%s: got %v, want %v", tc.desc, got, tc.want)
   583  			continue
   584  		}
   585  	}
   586  }
   587  
   588  // TestMove tests that the hinter.move method matches the output of the C
   589  // Freetype implementation.
   590  func TestMove(t *testing.T) {
   591  	h, p := hinter{}, Point{}
   592  	testCases := []struct {
   593  		pvX, pvY, fvX, fvY f2dot14
   594  		wantX, wantY       fixed.Int26_6
   595  	}{
   596  		{+0x4000, +0x0000, +0x4000, +0x0000, +1000, +0},
   597  		{+0x4000, +0x0000, -0x4000, +0x0000, +1000, +0},
   598  		{-0x4000, +0x0000, +0x4000, +0x0000, -1000, +0},
   599  		{-0x4000, +0x0000, -0x4000, +0x0000, -1000, +0},
   600  		{+0x0000, +0x4000, +0x0000, +0x4000, +0, +1000},
   601  		{+0x0000, +0x4000, +0x0000, -0x4000, +0, +1000},
   602  		{+0x4000, +0x0000, +0x2d41, +0x2d41, +1000, +1000},
   603  		{+0x4000, +0x0000, -0x2d41, +0x2d41, +1000, -1000},
   604  		{+0x4000, +0x0000, +0x2d41, -0x2d41, +1000, -1000},
   605  		{+0x4000, +0x0000, -0x2d41, -0x2d41, +1000, +1000},
   606  		{-0x4000, +0x0000, +0x2d41, +0x2d41, -1000, -1000},
   607  		{-0x4000, +0x0000, -0x2d41, +0x2d41, -1000, +1000},
   608  		{-0x4000, +0x0000, +0x2d41, -0x2d41, -1000, +1000},
   609  		{-0x4000, +0x0000, -0x2d41, -0x2d41, -1000, -1000},
   610  		{+0x376d, +0x2000, +0x2d41, +0x2d41, +732, +732},
   611  		{-0x376d, +0x2000, +0x2d41, +0x2d41, -2732, -2732},
   612  		{+0x376d, +0x2000, +0x2d41, -0x2d41, +2732, -2732},
   613  		{-0x376d, +0x2000, +0x2d41, -0x2d41, -732, +732},
   614  		{-0x376d, -0x2000, +0x2d41, +0x2d41, -732, -732},
   615  		{+0x376d, +0x2000, +0x4000, +0x0000, +1155, +0},
   616  		{+0x376d, +0x2000, +0x0000, +0x4000, +0, +2000},
   617  	}
   618  	for _, tc := range testCases {
   619  		p = Point{}
   620  		h.gs.pv = [2]f2dot14{tc.pvX, tc.pvY}
   621  		h.gs.fv = [2]f2dot14{tc.fvX, tc.fvY}
   622  		h.move(&p, 1000, true)
   623  		tx := p.Flags&flagTouchedX != 0
   624  		ty := p.Flags&flagTouchedY != 0
   625  		wantTX := tc.fvX != 0
   626  		wantTY := tc.fvY != 0
   627  		if p.X != tc.wantX || p.Y != tc.wantY || tx != wantTX || ty != wantTY {
   628  			t.Errorf("pv=%v, fv=%v\ngot  %d, %d, %t, %t\nwant %d, %d, %t, %t",
   629  				h.gs.pv, h.gs.fv, p.X, p.Y, tx, ty, tc.wantX, tc.wantY, wantTX, wantTY)
   630  			continue
   631  		}
   632  
   633  		// Check that p is aligned with the freedom vector.
   634  		a := int64(p.X) * int64(tc.fvY)
   635  		b := int64(p.Y) * int64(tc.fvX)
   636  		if a != b {
   637  			t.Errorf("pv=%v, fv=%v, p=%v not aligned with fv", h.gs.pv, h.gs.fv, p)
   638  			continue
   639  		}
   640  
   641  		// Check that the projected p is 1000 away from the origin.
   642  		dotProd := (int64(p.X)*int64(tc.pvX) + int64(p.Y)*int64(tc.pvY) + 1<<13) >> 14
   643  		if dotProd != 1000 {
   644  			t.Errorf("pv=%v, fv=%v, p=%v not 1000 from origin", h.gs.pv, h.gs.fv, p)
   645  			continue
   646  		}
   647  	}
   648  }
   649  
   650  // TestNormalize tests that the normalize function matches the output of the C
   651  // Freetype implementation.
   652  func TestNormalize(t *testing.T) {
   653  	testCases := [][2]f2dot14{
   654  		{-15895, 3974},
   655  		{-15543, 5181},
   656  		{-14654, 7327},
   657  		{-11585, 11585},
   658  		{0, 16384},
   659  		{11585, 11585},
   660  		{14654, 7327},
   661  		{15543, 5181},
   662  		{15895, 3974},
   663  		{16066, 3213},
   664  		{16161, 2694},
   665  		{16219, 2317},
   666  		{16257, 2032},
   667  		{16284, 1809},
   668  	}
   669  	for i, want := range testCases {
   670  		got := normalize(f2dot14(i)-4, 1)
   671  		if got != want {
   672  			t.Errorf("i=%d: got %v, want %v", i, got, want)
   673  		}
   674  	}
   675  }
   676  

View as plain text