Reviewed by Mark Rowe.
[WebKit-https.git] / WebCore / platform / graphics / chromium / FontCustomPlatformData.cpp
1 /*
2  * Copyright (C) 2007 Apple Computer, Inc.
3  * Copyright (c) 2007, 2008, 2009, Google Inc. All rights reserved.
4  * 
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met:
8  * 
9  *     * Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  *     * Redistributions in binary form must reproduce the above
12  * copyright notice, this list of conditions and the following disclaimer
13  * in the documentation and/or other materials provided with the
14  * distribution.
15  *     * Neither the name of Google Inc. nor the names of its
16  * contributors may be used to endorse or promote products derived from
17  * this software without specific prior written permission.
18  * 
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
31
32 #include "config.h"
33 #include "FontCustomPlatformData.h"
34
35 #if PLATFORM(WIN_OS)
36 #include "Base64.h"
37 #include "ChromiumBridge.h"
38 #include "OpenTypeUtilities.h"
39 #endif
40
41 #include "FontPlatformData.h"
42 #include "NotImplemented.h"
43 #include "SharedBuffer.h"
44
45 #if PLATFORM(WIN_OS)
46 #include <objbase.h>
47 #include <t2embapi.h>
48 #pragma comment(lib, "t2embed")
49 #endif
50
51 namespace WebCore {
52
53 FontCustomPlatformData::~FontCustomPlatformData()
54 {
55 #if PLATFORM(WIN_OS)
56     if (m_fontReference) {
57         if (m_name.isNull()) {
58             ULONG status;
59             TTDeleteEmbeddedFont(m_fontReference, 0, &status);
60         } else
61             RemoveFontMemResourceEx(m_fontReference);
62     }
63 #endif
64 }
65
66 FontPlatformData FontCustomPlatformData::fontPlatformData(int size, bool bold, bool italic, FontRenderingMode mode)
67 {
68 #if PLATFORM(WIN_OS)
69     ASSERT(m_fontReference);
70
71     LOGFONT logFont;
72     if (m_name.isNull())
73         TTGetNewFontName(&m_fontReference, logFont.lfFaceName, LF_FACESIZE, 0, 0);
74     else {
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
86     // FIXME: almost identical to FillLogFont in FontCacheWin.cpp.
87     // Need to refactor. 
88     logFont.lfHeight = -size;
89     logFont.lfWidth = 0;
90     logFont.lfEscapement = 0;
91     logFont.lfOrientation = 0;
92     logFont.lfUnderline = false;
93     logFont.lfStrikeOut = false;
94     logFont.lfCharSet = DEFAULT_CHARSET;
95     logFont.lfOutPrecision = OUT_TT_ONLY_PRECIS;
96     logFont.lfQuality = ChromiumBridge::layoutTestMode() ?
97                         NONANTIALIASED_QUALITY :
98                         DEFAULT_QUALITY; // Honor user's desktop settings.
99     logFont.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
100     logFont.lfItalic = italic;
101     logFont.lfWeight = bold ? 700 : 400;
102
103     HFONT hfont = CreateFontIndirect(&logFont);
104     return FontPlatformData(hfont, size);
105 #else
106     notImplemented();
107     return FontPlatformData();
108 #endif
109 }
110
111 #if PLATFORM(WIN_OS)
112 // FIXME: EOTStream class and static functions in this #if block are
113 // duplicated from platform/graphics/win/FontCustomPlatformData.cpp
114 // and need to be shared.
115
116 // Streams the concatenation of a header and font data.
117 class EOTStream {
118 public:
119     EOTStream(const EOTHeader& eotHeader, const SharedBuffer* fontData, size_t overlayDst, size_t overlaySrc, size_t overlayLength)
120         : m_eotHeader(eotHeader)
121         , m_fontData(fontData)
122         , m_overlayDst(overlayDst)
123         , m_overlaySrc(overlaySrc)
124         , m_overlayLength(overlayLength)
125         , m_offset(0)
126         , m_inHeader(true)
127     {
128     }
129
130     size_t read(void* buffer, size_t count);
131
132 private:
133     const EOTHeader& m_eotHeader;
134     const SharedBuffer* m_fontData;
135     size_t m_overlayDst;
136     size_t m_overlaySrc;
137     size_t m_overlayLength;
138     size_t m_offset;
139     bool m_inHeader;
140 };
141
142 size_t EOTStream::read(void* buffer, size_t count)
143 {
144     size_t bytesToRead = count;
145     if (m_inHeader) {
146         size_t bytesFromHeader = std::min(m_eotHeader.size() - m_offset, count);
147         memcpy(buffer, m_eotHeader.data() + m_offset, bytesFromHeader);
148         m_offset += bytesFromHeader;
149         bytesToRead -= bytesFromHeader;
150         if (m_offset == m_eotHeader.size()) {
151             m_inHeader = false;
152             m_offset = 0;
153         }
154     }
155     if (bytesToRead && !m_inHeader) {
156         size_t bytesFromData = std::min(m_fontData->size() - m_offset, bytesToRead);
157         memcpy(buffer, m_fontData->data() + m_offset, bytesFromData);
158         if (m_offset < m_overlayDst + m_overlayLength && m_offset + bytesFromData >= m_overlayDst) {
159             size_t dstOffset = std::max<int>(m_overlayDst - m_offset, 0);
160             size_t srcOffset = std::max<int>(0, m_offset - m_overlayDst);
161             size_t bytesToCopy = std::min(bytesFromData - dstOffset, m_overlayLength - srcOffset);
162             memcpy(reinterpret_cast<char*>(buffer) + dstOffset, m_fontData->data() + m_overlaySrc + srcOffset, bytesToCopy);
163         }
164         m_offset += bytesFromData;
165         bytesToRead -= bytesFromData;
166     }
167     return count - bytesToRead;
168 }
169
170 static unsigned long WINAPIV readEmbedProc(void* stream, void* buffer, unsigned long length)
171 {
172     return static_cast<EOTStream*>(stream)->read(buffer, length);
173 }
174
175 // Creates a unique and unpredictable font name, in order to avoid collisions and to
176 // not allow access from CSS.
177 static String createUniqueFontName()
178 {
179     Vector<char> fontUuid(sizeof(GUID));
180     CoCreateGuid(reinterpret_cast<GUID*>(fontUuid.data()));
181
182     Vector<char> fontNameVector;
183     base64Encode(fontUuid, fontNameVector);
184     ASSERT(fontNameVector.size() < LF_FACESIZE);
185     return String(fontNameVector.data(), fontNameVector.size());
186 }
187 #endif
188
189 FontCustomPlatformData* createFontCustomPlatformData(SharedBuffer* buffer)
190 {
191     ASSERT_ARG(buffer, buffer);
192
193 #if PLATFORM(WIN_OS)
194     // Introduce the font to GDI. AddFontMemResourceEx cannot be used, because it will pollute the process's
195     // font namespace (Windows has no API for creating an HFONT from data without exposing the font to the
196     // entire process first). TTLoadEmbeddedFont lets us override the font family name, so using a unique name
197     // we avoid namespace collisions.
198
199     String fontName = createUniqueFontName();
200
201     // TTLoadEmbeddedFont works only with Embedded OpenType (.eot) data,
202     // so we need to create an EOT header and prepend it to the font data.
203     EOTHeader eotHeader;
204     size_t overlayDst;
205     size_t overlaySrc;
206     size_t overlayLength;
207
208     if (!getEOTHeader(buffer, eotHeader, overlayDst, overlaySrc, overlayLength))
209         return 0;
210
211     HANDLE fontReference;
212     ULONG privStatus;
213     ULONG status;
214     EOTStream eotStream(eotHeader, buffer, overlayDst, overlaySrc, overlayLength);
215
216     LONG loadEmbeddedFontResult = TTLoadEmbeddedFont(&fontReference, TTLOAD_PRIVATE, &privStatus, LICENSE_PREVIEWPRINT, &status, readEmbedProc, &eotStream, const_cast<LPWSTR>(fontName.charactersWithNullTermination()), 0, 0);
217     if (loadEmbeddedFontResult == E_NONE)
218         fontName = String();
219     else {
220         fontReference = renameAndActivateFont(buffer, fontName);
221         if (!fontReference)
222             return 0;
223     }
224
225     return new FontCustomPlatformData(fontReference, fontName);
226 #else
227     notImplemented();;
228     return 0;
229 #endif
230 }
231
232 }