Home | History | Annotate | Download | only in skia
      1 /*
      2  * Copyright (C) 2007 Apple Computer, Inc.
      3  * Copyright (c) 2007, 2008, 2009, Google Inc. All rights reserved.
      4  * Copyright (C) 2010 Company 100, Inc.
      5  *
      6  * Redistribution and use in source and binary forms, with or without
      7  * modification, are permitted provided that the following conditions are
      8  * met:
      9  *
     10  *     * Redistributions of source code must retain the above copyright
     11  * notice, this list of conditions and the following disclaimer.
     12  *     * Redistributions in binary form must reproduce the above
     13  * copyright notice, this list of conditions and the following disclaimer
     14  * in the documentation and/or other materials provided with the
     15  * distribution.
     16  *     * Neither the name of Google Inc. nor the names of its
     17  * contributors may be used to endorse or promote products derived from
     18  * this software without specific prior written permission.
     19  *
     20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     23  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     24  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     25  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     26  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     30  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     31  */
     32 
     33 #include "config.h"
     34 #include "FontCustomPlatformData.h"
     35 
     36 #if OS(WINDOWS)
     37 #include "Base64.h"
     38 #include "OpenTypeUtilities.h"
     39 #include "PlatformBridge.h"
     40 #elif OS(LINUX) || OS(FREEBSD) || PLATFORM(BREWMP)
     41 #include "SkStream.h"
     42 #endif
     43 
     44 #include "FontPlatformData.h"
     45 #include "NotImplemented.h"
     46 #include "OpenTypeSanitizer.h"
     47 #include "SharedBuffer.h"
     48 
     49 #if OS(WINDOWS)
     50 #include <objbase.h>
     51 #elif OS(LINUX) || OS(FREEBSD) || PLATFORM(BREWMP)
     52 #include <cstring>
     53 #endif
     54 
     55 namespace WebCore {
     56 
     57 FontCustomPlatformData::~FontCustomPlatformData()
     58 {
     59 #if OS(WINDOWS)
     60     if (m_fontReference)
     61         RemoveFontMemResourceEx(m_fontReference);
     62 #elif OS(LINUX) || OS(FREEBSD) || PLATFORM(BREWMP)
     63     if (m_fontReference)
     64         m_fontReference->unref();
     65 #endif
     66 }
     67 
     68 FontPlatformData FontCustomPlatformData::fontPlatformData(int size, bool bold, bool italic, FontOrientation orientation,
     69                                                           TextOrientation textOrientation, FontWidthVariant, FontRenderingMode mode)
     70 {
     71 #if OS(WINDOWS)
     72     ASSERT(m_fontReference);
     73 
     74     LOGFONT logFont;
     75     // m_name comes from createUniqueFontName, which, in turn, gets
     76     // it from base64-encoded uuid (128-bit). So, m_name
     77     // can never be longer than LF_FACESIZE (32).
     78     if (m_name.length() + 1 >= LF_FACESIZE) {
     79         ASSERT_NOT_REACHED();
     80         return FontPlatformData();
     81     }
     82     memcpy(logFont.lfFaceName, m_name.charactersWithNullTermination(),
     83            sizeof(logFont.lfFaceName[0]) * (1 + m_name.length()));
     84 
     85     // FIXME: almost identical to FillLogFont in FontCacheWin.cpp.
     86     // Need to refactor.
     87     logFont.lfHeight = -size;
     88     logFont.lfWidth = 0;
     89     logFont.lfEscapement = 0;
     90     logFont.lfOrientation = 0;
     91     logFont.lfUnderline = false;
     92     logFont.lfStrikeOut = false;
     93     logFont.lfCharSet = DEFAULT_CHARSET;
     94     logFont.lfOutPrecision = OUT_TT_ONLY_PRECIS;
     95     logFont.lfQuality = PlatformBridge::layoutTestMode() ?
     96                         NONANTIALIASED_QUALITY :
     97                         DEFAULT_QUALITY; // Honor user's desktop settings.
     98     logFont.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
     99     logFont.lfItalic = italic;
    100     logFont.lfWeight = bold ? 700 : 400;
    101 
    102     HFONT hfont = CreateFontIndirect(&logFont);
    103     return FontPlatformData(hfont, size);
    104 #elif OS(LINUX) || OS(FREEBSD) || PLATFORM(BREWMP)
    105     ASSERT(m_fontReference);
    106     return FontPlatformData(m_fontReference, "", size, bold && !m_fontReference->isBold(), italic && !m_fontReference->isItalic(), orientation, textOrientation);
    107 #else
    108     notImplemented();
    109     return FontPlatformData();
    110 #endif
    111 }
    112 
    113 #if OS(WINDOWS)
    114 // Creates a unique and unpredictable font name, in order to avoid collisions and to
    115 // not allow access from CSS.
    116 static String createUniqueFontName()
    117 {
    118     GUID fontUuid;
    119     CoCreateGuid(&fontUuid);
    120 
    121     String fontName = base64Encode(reinterpret_cast<char*>(&fontUuid), sizeof(fontUuid));
    122     ASSERT(fontName.length() < LF_FACESIZE);
    123     return fontName;
    124 }
    125 #endif
    126 
    127 #if OS(LINUX) || OS(FREEBSD) || PLATFORM(BREWMP)
    128 class RemoteFontStream : public SkStream {
    129 public:
    130     explicit RemoteFontStream(PassRefPtr<SharedBuffer> buffer)
    131         : m_buffer(buffer)
    132         , m_offset(0)
    133     {
    134     }
    135 
    136     virtual ~RemoteFontStream()
    137     {
    138     }
    139 
    140     virtual bool rewind()
    141     {
    142         m_offset = 0;
    143         return true;
    144     }
    145 
    146     virtual size_t read(void* buffer, size_t size)
    147     {
    148         if (!buffer && !size) {
    149             // This is request for the length of the stream.
    150             return m_buffer->size();
    151         }
    152         // This is a request to read bytes or skip bytes (when buffer is 0).
    153         if (!m_buffer->data() || !m_buffer->size())
    154             return 0;
    155         size_t left = m_buffer->size() - m_offset;
    156         size_t bytesToConsume = std::min(left, size);
    157         if (buffer)
    158             std::memcpy(buffer, m_buffer->data() + m_offset, bytesToConsume);
    159         m_offset += bytesToConsume;
    160         return bytesToConsume;
    161     }
    162 
    163 private:
    164     RefPtr<SharedBuffer> m_buffer;
    165     size_t m_offset;
    166 };
    167 #endif
    168 
    169 FontCustomPlatformData* createFontCustomPlatformData(SharedBuffer* buffer)
    170 {
    171     ASSERT_ARG(buffer, buffer);
    172 
    173 #if ENABLE(OPENTYPE_SANITIZER)
    174     OpenTypeSanitizer sanitizer(buffer);
    175     RefPtr<SharedBuffer> transcodeBuffer = sanitizer.sanitize();
    176     if (!transcodeBuffer)
    177         return 0; // validation failed.
    178     buffer = transcodeBuffer.get();
    179 #endif
    180 
    181 #if OS(WINDOWS)
    182     // Introduce the font to GDI. AddFontMemResourceEx should be used with care, because it will pollute the process's
    183     // font namespace (Windows has no API for creating an HFONT from data without exposing the font to the
    184     // entire process first).
    185     String fontName = createUniqueFontName();
    186     HANDLE fontReference = renameAndActivateFont(buffer, fontName);
    187     if (!fontReference)
    188         return 0;
    189     return new FontCustomPlatformData(fontReference, fontName);
    190 #elif OS(LINUX) || OS(FREEBSD) || PLATFORM(BREWMP)
    191     RemoteFontStream* stream = new RemoteFontStream(buffer);
    192     SkTypeface* typeface = SkTypeface::CreateFromStream(stream);
    193     if (!typeface)
    194         return 0;
    195     return new FontCustomPlatformData(typeface);
    196 #else
    197     notImplemented();
    198     return 0;
    199 #endif
    200 }
    201 
    202 bool FontCustomPlatformData::supportsFormat(const String& format)
    203 {
    204     return equalIgnoringCase(format, "truetype") || equalIgnoringCase(format, "opentype")
    205 #if ENABLE(OPENTYPE_SANITIZER)
    206         || equalIgnoringCase(format, "woff")
    207 #endif
    208     ;
    209 }
    210 
    211 }
    212