gfx/2d/ScaledFontMac.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
     2  * This Source Code Form is subject to the terms of the Mozilla Public
     3  * License, v. 2.0. If a copy of the MPL was not distributed with this
     4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     6 #include "ScaledFontMac.h"
     7 #ifdef USE_SKIA
     8 #include "PathSkia.h"
     9 #include "skia/SkPaint.h"
    10 #include "skia/SkPath.h"
    11 #include "skia/SkTypeface_mac.h"
    12 #endif
    13 #include "DrawTargetCG.h"
    14 #include <vector>
    15 #include <dlfcn.h>
    17 // prototype for private API
    18 extern "C" {
    19 CGPathRef CGFontGetGlyphPath(CGFontRef fontRef, CGAffineTransform *textTransform, int unknown, CGGlyph glyph);
    20 };
    23 namespace mozilla {
    24 namespace gfx {
    26 ScaledFontMac::CTFontDrawGlyphsFuncT* ScaledFontMac::CTFontDrawGlyphsPtr = nullptr;
    27 bool ScaledFontMac::sSymbolLookupDone = false;
    29 ScaledFontMac::ScaledFontMac(CGFontRef aFont, Float aSize)
    30   : ScaledFontBase(aSize)
    31 {
    32   if (!sSymbolLookupDone) {
    33     CTFontDrawGlyphsPtr =
    34       (CTFontDrawGlyphsFuncT*)dlsym(RTLD_DEFAULT, "CTFontDrawGlyphs");
    35     sSymbolLookupDone = true;
    36   }
    38   // XXX: should we be taking a reference
    39   mFont = CGFontRetain(aFont);
    40   if (CTFontDrawGlyphsPtr != nullptr) {
    41     // only create mCTFont if we're going to be using the CTFontDrawGlyphs API
    42     mCTFont = CTFontCreateWithGraphicsFont(aFont, aSize, nullptr, nullptr);
    43   } else {
    44     mCTFont = nullptr;
    45   }
    46 }
    48 ScaledFontMac::~ScaledFontMac()
    49 {
    50   if (mCTFont) {
    51     CFRelease(mCTFont);
    52   }
    53   CGFontRelease(mFont);
    54 }
    56 #ifdef USE_SKIA
    57 SkTypeface* ScaledFontMac::GetSkTypeface()
    58 {
    59   if (!mTypeface) {
    60     if (mCTFont) {
    61       mTypeface = SkCreateTypefaceFromCTFont(mCTFont);
    62     } else {
    63       CTFontRef fontFace = CTFontCreateWithGraphicsFont(mFont, mSize, nullptr, nullptr);
    64       mTypeface = SkCreateTypefaceFromCTFont(fontFace);
    65       CFRelease(fontFace);
    66     }
    67   }
    68   return mTypeface;
    69 }
    70 #endif
    72 // private API here are the public options on OS X
    73 // CTFontCreatePathForGlyph
    74 // ATSUGlyphGetCubicPaths
    75 // we've used this in cairo sucessfully for some time.
    76 // Note: cairo dlsyms it. We could do that but maybe it's
    77 // safe just to use?
    79 TemporaryRef<Path>
    80 ScaledFontMac::GetPathForGlyphs(const GlyphBuffer &aBuffer, const DrawTarget *aTarget)
    81 {
    82   if (aTarget->GetType() == BackendType::COREGRAPHICS || aTarget->GetType() == BackendType::COREGRAPHICS_ACCELERATED) {
    83       CGMutablePathRef path = CGPathCreateMutable();
    85       for (unsigned int i = 0; i < aBuffer.mNumGlyphs; i++) {
    86           // XXX: we could probably fold both of these transforms together to avoid extra work
    87           CGAffineTransform flip = CGAffineTransformMakeScale(1, -1);
    88           CGPathRef glyphPath = ::CGFontGetGlyphPath(mFont, &flip, 0, aBuffer.mGlyphs[i].mIndex);
    90           CGAffineTransform matrix = CGAffineTransformMake(mSize, 0, 0, mSize,
    91                                                            aBuffer.mGlyphs[i].mPosition.x,
    92                                                            aBuffer.mGlyphs[i].mPosition.y);
    93           CGPathAddPath(path, &matrix, glyphPath);
    94           CGPathRelease(glyphPath);
    95       }
    96       TemporaryRef<Path> ret = new PathCG(path, FillRule::FILL_WINDING);
    97       CGPathRelease(path);
    98       return ret;
    99   } else {
   100       return ScaledFontBase::GetPathForGlyphs(aBuffer, aTarget);
   101   }
   102 }
   104 void
   105 ScaledFontMac::CopyGlyphsToBuilder(const GlyphBuffer &aBuffer, PathBuilder *aBuilder, BackendType aBackendType, const Matrix *aTransformHint)
   106 {
   107   if (!(aBackendType == BackendType::COREGRAPHICS || aBackendType == BackendType::COREGRAPHICS_ACCELERATED)) {
   108     ScaledFontBase::CopyGlyphsToBuilder(aBuffer, aBuilder, aBackendType, aTransformHint);
   109     return;
   110   }
   112   PathBuilderCG *pathBuilderCG =
   113     static_cast<PathBuilderCG*>(aBuilder);
   114   // XXX: check builder type
   115   for (unsigned int i = 0; i < aBuffer.mNumGlyphs; i++) {
   116     // XXX: we could probably fold both of these transforms together to avoid extra work
   117     CGAffineTransform flip = CGAffineTransformMakeScale(1, -1);
   118     CGPathRef glyphPath = ::CGFontGetGlyphPath(mFont, &flip, 0, aBuffer.mGlyphs[i].mIndex);
   120     CGAffineTransform matrix = CGAffineTransformMake(mSize, 0, 0, mSize,
   121                                                      aBuffer.mGlyphs[i].mPosition.x,
   122                                                      aBuffer.mGlyphs[i].mPosition.y);
   123     CGPathAddPath(pathBuilderCG->mCGPath, &matrix, glyphPath);
   124     CGPathRelease(glyphPath);
   125   }
   126 }
   128 uint32_t
   129 CalcTableChecksum(const uint32_t *tableStart, uint32_t length, bool skipChecksumAdjust = false)
   130 {
   131     uint32_t sum = 0L;
   132     const uint32_t *table = tableStart;
   133     const uint32_t *end = table+((length+3) & ~3) / sizeof(uint32_t);
   134     while (table < end) {
   135         if (skipChecksumAdjust && (table - tableStart) == 2) {
   136             table++;
   137         } else {
   138             sum += CFSwapInt32BigToHost(*table++);
   139         }
   140     }
   141     return sum;
   142 }
   144 struct TableRecord {
   145     uint32_t tag;
   146     uint32_t checkSum;
   147     uint32_t offset;
   148     uint32_t length;
   149     CFDataRef data;
   150 };
   152 int maxPow2LessThan(int a)
   153 {
   154     int x = 1;
   155     int shift = 0;
   156     while ((x<<(shift+1)) < a) {
   157         shift++;
   158     }
   159     return shift;
   160 }
   162 struct writeBuf
   163 {
   164     writeBuf(int size)
   165     {
   166         this->data = new unsigned char [size];
   167         this->offset = 0;
   168     }
   169     ~writeBuf() {
   170         delete this->data;
   171     }
   173     template <class T>
   174     void writeElement(T a)
   175     {
   176         *reinterpret_cast<T*>(&this->data[this->offset]) = a;
   177         this->offset += sizeof(T);
   178     }
   180     void writeMem(const void *data, unsigned long length)
   181     {
   182         memcpy(&this->data[this->offset], data, length);
   183         this->offset += length;
   184     }
   186     void align()
   187     {
   188         while (this->offset & 3) {
   189             this->data[this->offset] = 0;
   190             this->offset++;
   191         }
   192     }
   194     unsigned char *data;
   195     int offset;
   196 };
   198 bool
   199 ScaledFontMac::GetFontFileData(FontFileDataOutput aDataCallback, void *aBaton)
   200 {
   201     // We'll reconstruct a TTF font from the tables we can get from the CGFont
   202     CFArrayRef tags = CGFontCopyTableTags(mFont);
   203     CFIndex count = CFArrayGetCount(tags);
   205     TableRecord *records = new TableRecord[count];
   206     uint32_t offset = 0;
   207     offset += sizeof(uint32_t)*3;
   208     offset += sizeof(uint32_t)*4*count;
   209     bool CFF = false;
   210     for (CFIndex i = 0; i<count; i++) {
   211         uint32_t tag = (uint32_t)(uintptr_t)CFArrayGetValueAtIndex(tags, i);
   212         if (tag == 0x43464620) // 'CFF '
   213             CFF = true;
   214         CFDataRef data = CGFontCopyTableForTag(mFont, tag);
   215         records[i].tag = tag;
   216         records[i].offset = offset;
   217         records[i].data = data;
   218         records[i].length = CFDataGetLength(data);
   219         bool skipChecksumAdjust = (tag == 0x68656164); // 'head'
   220         records[i].checkSum = CalcTableChecksum(reinterpret_cast<const uint32_t*>(CFDataGetBytePtr(data)),
   221                                                 records[i].length, skipChecksumAdjust);
   222         offset += records[i].length;
   223         // 32 bit align the tables
   224         offset = (offset + 3) & ~3;
   225     }
   226     CFRelease(tags);
   228     struct writeBuf buf(offset);
   229     // write header/offset table
   230     if (CFF) {
   231       buf.writeElement(CFSwapInt32HostToBig(0x4f54544f));
   232     } else {
   233       buf.writeElement(CFSwapInt32HostToBig(0x00010000));
   234     }
   235     buf.writeElement(CFSwapInt16HostToBig(count));
   236     buf.writeElement(CFSwapInt16HostToBig((1<<maxPow2LessThan(count))*16));
   237     buf.writeElement(CFSwapInt16HostToBig(maxPow2LessThan(count)));
   238     buf.writeElement(CFSwapInt16HostToBig(count*16-((1<<maxPow2LessThan(count))*16)));
   240     // write table record entries
   241     for (CFIndex i = 0; i<count; i++) {
   242         buf.writeElement(CFSwapInt32HostToBig(records[i].tag));
   243         buf.writeElement(CFSwapInt32HostToBig(records[i].checkSum));
   244         buf.writeElement(CFSwapInt32HostToBig(records[i].offset));
   245         buf.writeElement(CFSwapInt32HostToBig(records[i].length));
   246     }
   248     // write tables
   249     int checkSumAdjustmentOffset = 0;
   250     for (CFIndex i = 0; i<count; i++) {
   251         if (records[i].tag == 0x68656164) {
   252             checkSumAdjustmentOffset = buf.offset + 2*4;
   253         }
   254         buf.writeMem(CFDataGetBytePtr(records[i].data), CFDataGetLength(records[i].data));
   255         buf.align();
   256         CFRelease(records[i].data);
   257     }
   258     delete[] records;
   260     // clear the checksumAdjust field before checksumming the whole font
   261     memset(&buf.data[checkSumAdjustmentOffset], 0, sizeof(uint32_t));
   262     uint32_t fontChecksum = CFSwapInt32HostToBig(0xb1b0afba - CalcTableChecksum(reinterpret_cast<const uint32_t*>(buf.data), offset));
   263     // set checkSumAdjust to the computed checksum
   264     memcpy(&buf.data[checkSumAdjustmentOffset], &fontChecksum, sizeof(fontChecksum));
   266     // we always use an index of 0
   267     aDataCallback(buf.data, buf.offset, 0, mSize, aBaton);
   269     return true;
   271 }
   273 }
   274 }

mercurial