Home | History | Annotate | Download | only in tests
      1 /*
      2  * Copyright 2012 Google Inc.
      3  *
      4  * Use of this source code is governed by a BSD-style license that can be
      5  * found in the LICENSE file.
      6  */
      7 
      8 #include "Test.h"
      9 #include "SkPaint.h"
     10 #include "SkTypeface.h"
     11 #include "SkEndian.h"
     12 
     13 //#define DUMP_TABLES
     14 
     15 #define kFontTableTag_head          SkSetFourByteTag('h', 'e', 'a', 'd')
     16 #define kFontTableTag_hhea          SkSetFourByteTag('h', 'h', 'e', 'a')
     17 #define kFontTableTag_maxp          SkSetFourByteTag('m', 'a', 'x', 'p')
     18 
     19 static const struct TagSize {
     20     SkFontTableTag  fTag;
     21     size_t          fSize;
     22 } gKnownTableSizes[] = {
     23     {   kFontTableTag_head,         54 },
     24     {   kFontTableTag_hhea,         36 },
     25     {   kFontTableTag_maxp,         32 },
     26 };
     27 
     28 static void test_unitsPerEm(skiatest::Reporter* reporter, SkTypeface* face) {
     29     int upem = face->getUnitsPerEm();
     30     if (0 == upem) return;
     31 
     32     size_t size = face->getTableSize(kFontTableTag_head);
     33     if (size) {
     34         SkAutoMalloc storage(size);
     35         char* ptr = (char*)storage.get();
     36         face->getTableData(kFontTableTag_head, 0, size, ptr);
     37         // unitsPerEm is at offset 18 into the 'head' table.
     38         int upem2 = SkEndian_SwapBE16(*(uint16_t*)&ptr[18]);
     39         REPORTER_ASSERT(reporter, upem2 == upem);
     40     }
     41 }
     42 
     43 static void test_tables(skiatest::Reporter* reporter, SkTypeface* face) {
     44     if (false) { // avoid bit rot, suppress warning
     45         SkFontID fontID = face->uniqueID();
     46         REPORTER_ASSERT(reporter, fontID);
     47     }
     48 
     49     int count = face->countTables();
     50 
     51     SkAutoTMalloc<SkFontTableTag> storage(count);
     52     SkFontTableTag* tags = storage.get();
     53 
     54     int count2 = face->getTableTags(tags);
     55     REPORTER_ASSERT(reporter, count2 == count);
     56 
     57     for (int i = 0; i < count; ++i) {
     58         size_t size = face->getTableSize(tags[i]);
     59         REPORTER_ASSERT(reporter, size > 0);
     60 
     61 #ifdef DUMP_TABLES
     62         char name[5];
     63         name[0] = (tags[i] >> 24) & 0xFF;
     64         name[1] = (tags[i] >> 16) & 0xFF;
     65         name[2] = (tags[i] >>  8) & 0xFF;
     66         name[3] = (tags[i] >>  0) & 0xFF;
     67         name[4] = 0;
     68         SkDebugf("%s %d\n", name, size);
     69 #endif
     70 
     71         for (size_t j = 0; j < SK_ARRAY_COUNT(gKnownTableSizes); ++j) {
     72             if (gKnownTableSizes[j].fTag == tags[i]) {
     73                 REPORTER_ASSERT(reporter, gKnownTableSizes[j].fSize == size);
     74             }
     75         }
     76 
     77         // do we get the same size from GetTableData and GetTableSize
     78         {
     79             SkAutoMalloc data(size);
     80             size_t size2 = face->getTableData(tags[i], 0, size, data.get());
     81             REPORTER_ASSERT(reporter, size2 == size);
     82         }
     83     }
     84 }
     85 
     86 static void test_tables(skiatest::Reporter* reporter) {
     87     static const char* const gNames[] = {
     88         NULL,   // default font
     89         "Arial", "Times", "Times New Roman", "Helvetica", "Courier",
     90         "Courier New", "Terminal", "MS Sans Serif",
     91     };
     92 
     93     for (size_t i = 0; i < SK_ARRAY_COUNT(gNames); ++i) {
     94         SkTypeface* face = SkTypeface::CreateFromName(gNames[i],
     95                                                       SkTypeface::kNormal);
     96         if (face) {
     97 #ifdef DUMP_TABLES
     98             SkDebugf("%s\n", gNames[i]);
     99 #endif
    100             test_tables(reporter, face);
    101             test_unitsPerEm(reporter, face);
    102             face->unref();
    103         }
    104     }
    105 }
    106 
    107 /*
    108  * Verifies that the advance values returned by generateAdvance and
    109  * generateMetrics match.
    110  */
    111 static void test_advances(skiatest::Reporter* reporter) {
    112     static const char* const faces[] = {
    113         NULL,   // default font
    114         "Arial", "Times", "Times New Roman", "Helvetica", "Courier",
    115         "Courier New", "Verdana", "monospace",
    116     };
    117 
    118     static const struct {
    119         SkPaint::Hinting    hinting;
    120         unsigned            flags;
    121     } settings[] = {
    122         { SkPaint::kNo_Hinting,     0                               },
    123         { SkPaint::kNo_Hinting,     SkPaint::kLinearText_Flag       },
    124         { SkPaint::kNo_Hinting,     SkPaint::kSubpixelText_Flag     },
    125         { SkPaint::kSlight_Hinting, 0                               },
    126         { SkPaint::kSlight_Hinting, SkPaint::kLinearText_Flag       },
    127         { SkPaint::kSlight_Hinting, SkPaint::kSubpixelText_Flag     },
    128         { SkPaint::kNormal_Hinting, 0                               },
    129         { SkPaint::kNormal_Hinting, SkPaint::kLinearText_Flag       },
    130         { SkPaint::kNormal_Hinting, SkPaint::kSubpixelText_Flag     },
    131     };
    132 
    133     static const struct {
    134         SkScalar    fScaleX;
    135         SkScalar    fSkewX;
    136     } gScaleRec[] = {
    137         { SK_Scalar1, 0 },
    138         { SK_Scalar1/2, 0 },
    139         // these two exercise obliquing (skew)
    140         { SK_Scalar1, -SK_Scalar1/4 },
    141         { SK_Scalar1/2, -SK_Scalar1/4 },
    142     };
    143 
    144     SkPaint paint;
    145     char txt[] = "long.text.with.lots.of.dots.";
    146 
    147     for (size_t i = 0; i < SK_ARRAY_COUNT(faces); i++) {
    148         SkTypeface* face = SkTypeface::CreateFromName(faces[i], SkTypeface::kNormal);
    149         paint.setTypeface(face);
    150 
    151         for (size_t j = 0; j  < SK_ARRAY_COUNT(settings); j++) {
    152             paint.setHinting(settings[j].hinting);
    153             paint.setLinearText((settings[j].flags & SkPaint::kLinearText_Flag) != 0);
    154             paint.setSubpixelText((settings[j].flags & SkPaint::kSubpixelText_Flag) != 0);
    155 
    156             for (size_t k = 0; k < SK_ARRAY_COUNT(gScaleRec); ++k) {
    157                 paint.setTextScaleX(gScaleRec[k].fScaleX);
    158                 paint.setTextSkewX(gScaleRec[k].fSkewX);
    159 
    160                 SkRect bounds;
    161 
    162                 // For no hinting and light hinting this should take the
    163                 // optimized generateAdvance path.
    164                 SkScalar width1 = paint.measureText(txt, strlen(txt));
    165 
    166                 // Requesting the bounds forces a generateMetrics call.
    167                 SkScalar width2 = paint.measureText(txt, strlen(txt), &bounds);
    168 
    169                 // SkDebugf("Font: %s, generateAdvance: %f, generateMetrics: %f\n",
    170                 //    faces[i], SkScalarToFloat(width1), SkScalarToFloat(width2));
    171 
    172                 REPORTER_ASSERT(reporter, width1 == width2);
    173             }
    174         }
    175     }
    176 }
    177 
    178 static void TestFontHost(skiatest::Reporter* reporter) {
    179     test_tables(reporter);
    180     test_advances(reporter);
    181 }
    182 
    183 // need tests for SkStrSearch
    184 
    185 #include "TestClassDef.h"
    186 DEFINE_TESTCLASS("FontHost", FontHostTestClass, TestFontHost)
    187