2010-12-05 21:38:12 +03:00
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* ***** BEGIN LICENSE BLOCK *****
2007-12-28 04:28:26 +03:00
* Version : MPL 1.1 / GPL 2.0 / LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 ( the " License " ) ; you may not use this file except in compliance with
* the License . You may obtain a copy of the License at
* http : //www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an " AS IS " basis ,
* WITHOUT WARRANTY OF ANY KIND , either express or implied . See the License
* for the specific language governing rights and limitations under the
* License .
*
* The Original Code is thebes gfx code .
*
2009-12-22 00:50:30 +03:00
* The Initial Developer of the Original Code is Mozilla Foundation .
2009-08-16 17:52:12 +04:00
* Portions created by the Initial Developer are Copyright ( C ) 2007 - 2009
2007-12-28 04:28:26 +03:00
* the Initial Developer . All Rights Reserved .
*
* Contributor ( s ) :
* Stuart Parmenter < stuart @ mozilla . com >
* John Daggett < jdaggett @ mozilla . com >
2009-08-16 17:52:12 +04:00
* Jonathan Kew < jfkthame @ gmail . com >
2007-12-28 04:28:26 +03:00
*
* Alternatively , the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later ( the " GPL " ) , or
* the GNU Lesser General Public License Version 2.1 or later ( the " LGPL " ) ,
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above . If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL , and not to allow others to
* use your version of this file under the terms of the MPL , indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL . If you do not delete
* the provisions above , a recipient may use your version of this file under
* the terms of any one of the MPL , the GPL or the LGPL .
*
* * * * * * END LICENSE BLOCK * * * * * */
# include "gfxFontUtils.h"
2008-02-26 11:00:44 +03:00
# include "nsServiceManagerUtils.h"
2011-06-12 06:30:16 +04:00
# include "mozilla/Preferences.h"
2008-10-01 07:01:53 +04:00
# include "nsIStreamBufferAccess.h"
2009-03-11 04:00:44 +03:00
# include "nsIUUIDGenerator.h"
2008-12-22 08:01:14 +03:00
# include "nsMemory.h"
2009-08-16 17:52:12 +04:00
# include "nsICharsetConverterManager.h"
2007-12-28 04:28:26 +03:00
2009-03-11 04:00:44 +03:00
# include "plbase64.h"
2009-08-30 17:55:24 +04:00
# include "woff.h"
2009-04-02 12:06:33 +04:00
# ifdef XP_MACOSX
# include <CoreFoundation/CoreFoundation.h>
# endif
2009-03-11 04:00:44 +03:00
2007-12-28 04:28:26 +03:00
# define NO_RANGE_FOUND 126 // bit 126 in the font unicode ranges is required to be 0
2010-06-11 23:14:38 +04:00
# define UNICODE_BMP_LIMIT 0x10000
using namespace mozilla ; // for the AutoSwap_* types
2007-12-28 04:28:26 +03:00
/* Unicode subrange table
2011-01-21 19:44:33 +03:00
* from : http : //msdn.microsoft.com/en-us/library/dd374090
2007-12-28 04:28:26 +03:00
*
2011-01-21 19:44:33 +03:00
* Edit the text to extend the initial digit , then use something like :
* perl - pi - e ' s / ^ ( \ d + ) \ t ( [ \ dA - Fa - f ] + ) \ s + - \ s + ( [ \ dA - Fa - f ] + ) \ s + \ b ( [ a - zA - Z0 - 9 \ ( \ ) \ - ] + ) / { \ 1 , 0 x \ 2 , 0 x \ 3 , \ " \4 \" },/' < unicoderange.txt
2007-12-28 04:28:26 +03:00
* to generate the below list .
*/
struct UnicodeRangeTableEntry
{
PRUint8 bit ;
PRUint32 start ;
PRUint32 end ;
const char * info ;
} ;
2011-01-21 19:44:33 +03:00
static struct UnicodeRangeTableEntry gUnicodeRanges [ ] = {
2007-12-28 04:28:26 +03:00
{ 0 , 0x0000 , 0x007F , " Basic Latin " } ,
{ 1 , 0x0080 , 0x00FF , " Latin-1 Supplement " } ,
{ 2 , 0x0100 , 0x017F , " Latin Extended-A " } ,
{ 3 , 0x0180 , 0x024F , " Latin Extended-B " } ,
{ 4 , 0x0250 , 0x02AF , " IPA Extensions " } ,
{ 4 , 0x1D00 , 0x1D7F , " Phonetic Extensions " } ,
{ 4 , 0x1D80 , 0x1DBF , " Phonetic Extensions Supplement " } ,
{ 5 , 0x02B0 , 0x02FF , " Spacing Modifier Letters " } ,
{ 5 , 0xA700 , 0xA71F , " Modifier Tone Letters " } ,
2011-01-21 19:44:33 +03:00
{ 6 , 0x0300 , 0x036F , " Combining Diacritical Marks " } ,
2007-12-28 04:28:26 +03:00
{ 6 , 0x1DC0 , 0x1DFF , " Combining Diacritical Marks Supplement " } ,
{ 7 , 0x0370 , 0x03FF , " Greek and Coptic " } ,
{ 8 , 0x2C80 , 0x2CFF , " Coptic " } ,
{ 9 , 0x0400 , 0x04FF , " Cyrillic " } ,
2011-01-21 19:44:33 +03:00
{ 9 , 0x0500 , 0x052F , " Cyrillic Supplement " } ,
{ 9 , 0x2DE0 , 0x2DFF , " Cyrillic Extended-A " } ,
{ 9 , 0xA640 , 0xA69F , " Cyrillic Extended-B " } ,
2007-12-28 04:28:26 +03:00
{ 10 , 0x0530 , 0x058F , " Armenian " } ,
2011-01-21 19:44:33 +03:00
{ 11 , 0x0590 , 0x05FF , " Hebrew " } ,
{ 12 , 0xA500 , 0xA63F , " Vai " } ,
{ 13 , 0x0600 , 0x06FF , " Arabic " } ,
2007-12-28 04:28:26 +03:00
{ 13 , 0x0750 , 0x077F , " Arabic Supplement " } ,
2011-01-21 19:44:33 +03:00
{ 14 , 0x07C0 , 0x07FF , " NKo " } ,
2007-12-28 04:28:26 +03:00
{ 15 , 0x0900 , 0x097F , " Devanagari " } ,
{ 16 , 0x0980 , 0x09FF , " Bengali " } ,
{ 17 , 0x0A00 , 0x0A7F , " Gurmukhi " } ,
{ 18 , 0x0A80 , 0x0AFF , " Gujarati " } ,
{ 19 , 0x0B00 , 0x0B7F , " Oriya " } ,
{ 20 , 0x0B80 , 0x0BFF , " Tamil " } ,
{ 21 , 0x0C00 , 0x0C7F , " Telugu " } ,
{ 22 , 0x0C80 , 0x0CFF , " Kannada " } ,
{ 23 , 0x0D00 , 0x0D7F , " Malayalam " } ,
{ 24 , 0x0E00 , 0x0E7F , " Thai " } ,
{ 25 , 0x0E80 , 0x0EFF , " Lao " } ,
{ 26 , 0x10A0 , 0x10FF , " Georgian " } ,
{ 26 , 0x2D00 , 0x2D2F , " Georgian Supplement " } ,
{ 27 , 0x1B00 , 0x1B7F , " Balinese " } ,
{ 28 , 0x1100 , 0x11FF , " Hangul Jamo " } ,
{ 29 , 0x1E00 , 0x1EFF , " Latin Extended Additional " } ,
{ 29 , 0x2C60 , 0x2C7F , " Latin Extended-C " } ,
2011-01-21 19:44:33 +03:00
{ 29 , 0xA720 , 0xA7FF , " Latin Extended-D " } ,
2007-12-28 04:28:26 +03:00
{ 30 , 0x1F00 , 0x1FFF , " Greek Extended " } ,
{ 31 , 0x2000 , 0x206F , " General Punctuation " } ,
{ 31 , 0x2E00 , 0x2E7F , " Supplemental Punctuation " } ,
2011-01-21 19:44:33 +03:00
{ 32 , 0x2070 , 0x209F , " Superscripts And Subscripts " } ,
2007-12-28 04:28:26 +03:00
{ 33 , 0x20A0 , 0x20CF , " Currency Symbols " } ,
2011-01-21 19:44:33 +03:00
{ 34 , 0x20D0 , 0x20FF , " Combining Diacritical Marks For Symbols " } ,
{ 35 , 0x2100 , 0x214F , " Letterlike Symbols " } ,
2007-12-28 04:28:26 +03:00
{ 36 , 0x2150 , 0x218F , " Number Forms " } ,
{ 37 , 0x2190 , 0x21FF , " Arrows " } ,
{ 37 , 0x27F0 , 0x27FF , " Supplemental Arrows-A " } ,
{ 37 , 0x2900 , 0x297F , " Supplemental Arrows-B " } ,
{ 37 , 0x2B00 , 0x2BFF , " Miscellaneous Symbols and Arrows " } ,
{ 38 , 0x2200 , 0x22FF , " Mathematical Operators " } ,
{ 38 , 0x27C0 , 0x27EF , " Miscellaneous Mathematical Symbols-A " } ,
{ 38 , 0x2980 , 0x29FF , " Miscellaneous Mathematical Symbols-B " } ,
{ 38 , 0x2A00 , 0x2AFF , " Supplemental Mathematical Operators " } ,
{ 39 , 0x2300 , 0x23FF , " Miscellaneous Technical " } ,
{ 40 , 0x2400 , 0x243F , " Control Pictures " } ,
{ 41 , 0x2440 , 0x245F , " Optical Character Recognition " } ,
{ 42 , 0x2460 , 0x24FF , " Enclosed Alphanumerics " } ,
{ 43 , 0x2500 , 0x257F , " Box Drawing " } ,
{ 44 , 0x2580 , 0x259F , " Block Elements " } ,
{ 45 , 0x25A0 , 0x25FF , " Geometric Shapes " } ,
{ 46 , 0x2600 , 0x26FF , " Miscellaneous Symbols " } ,
{ 47 , 0x2700 , 0x27BF , " Dingbats " } ,
2011-01-21 19:44:33 +03:00
{ 48 , 0x3000 , 0x303F , " CJK Symbols And Punctuation " } ,
2007-12-28 04:28:26 +03:00
{ 49 , 0x3040 , 0x309F , " Hiragana " } ,
{ 50 , 0x30A0 , 0x30FF , " Katakana " } ,
{ 50 , 0x31F0 , 0x31FF , " Katakana Phonetic Extensions " } ,
{ 51 , 0x3100 , 0x312F , " Bopomofo " } ,
2011-01-21 19:44:33 +03:00
{ 50 , 0x31A0 , 0x31BF , " Bopomofo Extended " } ,
2007-12-28 04:28:26 +03:00
{ 52 , 0x3130 , 0x318F , " Hangul Compatibility Jamo " } ,
{ 53 , 0xA840 , 0xA87F , " Phags-pa " } ,
2011-01-21 19:44:33 +03:00
{ 54 , 0x3200 , 0x32FF , " Enclosed CJK Letters And Months " } ,
2007-12-28 04:28:26 +03:00
{ 55 , 0x3300 , 0x33FF , " CJK Compatibility " } ,
2011-01-21 19:44:33 +03:00
{ 56 , 0xAC00 , 0xD7AF , " Hangul Syllables " } ,
{ 57 , 0xD800 , 0xDFFF , " Non-Plane 0 " } ,
2007-12-28 04:28:26 +03:00
{ 58 , 0x10900 , 0x1091F , " Phoenician " } ,
{ 59 , 0x2E80 , 0x2EFF , " CJK Radicals Supplement " } ,
{ 59 , 0x2F00 , 0x2FDF , " Kangxi Radicals " } ,
{ 59 , 0x2FF0 , 0x2FFF , " Ideographic Description Characters " } ,
{ 59 , 0x3190 , 0x319F , " Kanbun " } ,
{ 59 , 0x3400 , 0x4DBF , " CJK Unified Ideographs Extension A " } ,
{ 59 , 0x4E00 , 0x9FFF , " CJK Unified Ideographs " } ,
{ 59 , 0x20000 , 0x2A6DF , " CJK Unified Ideographs Extension B " } ,
2011-01-21 19:44:33 +03:00
{ 60 , 0xE000 , 0xF8FF , " Private Use Area " } ,
{ 61 , 0x31C0 , 0x31EF , " CJK Strokes " } ,
2007-12-28 04:28:26 +03:00
{ 61 , 0xF900 , 0xFAFF , " CJK Compatibility Ideographs " } ,
{ 61 , 0x2F800 , 0x2FA1F , " CJK Compatibility Ideographs Supplement " } ,
2011-01-21 19:44:33 +03:00
{ 62 , 0xFB00 , 0xFB4F , " Alphabetic Presentation Forms " } ,
2007-12-28 04:28:26 +03:00
{ 63 , 0xFB50 , 0xFDFF , " Arabic Presentation Forms-A " } ,
{ 64 , 0xFE20 , 0xFE2F , " Combining Half Marks " } ,
{ 65 , 0xFE10 , 0xFE1F , " Vertical Forms " } ,
{ 65 , 0xFE30 , 0xFE4F , " CJK Compatibility Forms " } ,
{ 66 , 0xFE50 , 0xFE6F , " Small Form Variants " } ,
2011-01-21 19:44:33 +03:00
{ 67 , 0xFE70 , 0xFEFF , " Arabic Presentation Forms-B " } ,
{ 68 , 0xFF00 , 0xFFEF , " Halfwidth And Fullwidth Forms " } ,
2007-12-28 04:28:26 +03:00
{ 69 , 0xFFF0 , 0xFFFF , " Specials " } ,
{ 70 , 0x0F00 , 0x0FFF , " Tibetan " } ,
{ 71 , 0x0700 , 0x074F , " Syriac " } ,
{ 72 , 0x0780 , 0x07BF , " Thaana " } ,
{ 73 , 0x0D80 , 0x0DFF , " Sinhala " } ,
{ 74 , 0x1000 , 0x109F , " Myanmar " } ,
{ 75 , 0x1200 , 0x137F , " Ethiopic " } ,
{ 75 , 0x1380 , 0x139F , " Ethiopic Supplement " } ,
{ 75 , 0x2D80 , 0x2DDF , " Ethiopic Extended " } ,
{ 76 , 0x13A0 , 0x13FF , " Cherokee " } ,
2011-01-21 19:44:33 +03:00
{ 77 , 0x1400 , 0x167F , " Unified Canadian Aboriginal Syllabics " } ,
2007-12-28 04:28:26 +03:00
{ 78 , 0x1680 , 0x169F , " Ogham " } ,
{ 79 , 0x16A0 , 0x16FF , " Runic " } ,
{ 80 , 0x1780 , 0x17FF , " Khmer " } ,
{ 80 , 0x19E0 , 0x19FF , " Khmer Symbols " } ,
{ 81 , 0x1800 , 0x18AF , " Mongolian " } ,
2011-01-21 19:44:33 +03:00
{ 82 , 0x2800 , 0x28FF , " Braille Patterns " } ,
{ 83 , 0xA000 , 0xA48F , " Yi Syllables " } ,
2007-12-28 04:28:26 +03:00
{ 83 , 0xA490 , 0xA4CF , " Yi Radicals " } ,
{ 84 , 0x1700 , 0x171F , " Tagalog " } ,
{ 84 , 0x1720 , 0x173F , " Hanunoo " } ,
{ 84 , 0x1740 , 0x175F , " Buhid " } ,
{ 84 , 0x1760 , 0x177F , " Tagbanwa " } ,
{ 85 , 0x10300 , 0x1032F , " Old Italic " } ,
{ 86 , 0x10330 , 0x1034F , " Gothic " } ,
2011-01-21 19:44:33 +03:00
{ 87 , 0x10400 , 0x1044F , " Deseret " } ,
2007-12-28 04:28:26 +03:00
{ 88 , 0x1D000 , 0x1D0FF , " Byzantine Musical Symbols " } ,
{ 88 , 0x1D100 , 0x1D1FF , " Musical Symbols " } ,
{ 88 , 0x1D200 , 0x1D24F , " Ancient Greek Musical Notation " } ,
{ 89 , 0x1D400 , 0x1D7FF , " Mathematical Alphanumeric Symbols " } ,
2011-01-21 19:44:33 +03:00
{ 90 , 0xFF000 , 0xFFFFD , " Private Use (plane 15) " } ,
{ 90 , 0x100000 , 0x10FFFD , " Private Use (plane 16) " } ,
2007-12-28 04:28:26 +03:00
{ 91 , 0xFE00 , 0xFE0F , " Variation Selectors " } ,
{ 91 , 0xE0100 , 0xE01EF , " Variation Selectors Supplement " } ,
{ 92 , 0xE0000 , 0xE007F , " Tags " } ,
{ 93 , 0x1900 , 0x194F , " Limbu " } ,
{ 94 , 0x1950 , 0x197F , " Tai Le " } ,
{ 95 , 0x1980 , 0x19DF , " New Tai Lue " } ,
{ 96 , 0x1A00 , 0x1A1F , " Buginese " } ,
{ 97 , 0x2C00 , 0x2C5F , " Glagolitic " } ,
2011-01-21 19:44:33 +03:00
{ 98 , 0x2D30 , 0x2D7F , " Tifinagh " } ,
2007-12-28 04:28:26 +03:00
{ 99 , 0x4DC0 , 0x4DFF , " Yijing Hexagram Symbols " } ,
{ 100 , 0xA800 , 0xA82F , " Syloti Nagri " } ,
{ 101 , 0x10000 , 0x1007F , " Linear B Syllabary " } ,
{ 101 , 0x10080 , 0x100FF , " Linear B Ideograms " } ,
{ 101 , 0x10100 , 0x1013F , " Aegean Numbers " } ,
{ 102 , 0x10140 , 0x1018F , " Ancient Greek Numbers " } ,
{ 103 , 0x10380 , 0x1039F , " Ugaritic " } ,
{ 104 , 0x103A0 , 0x103DF , " Old Persian " } ,
{ 105 , 0x10450 , 0x1047F , " Shavian " } ,
{ 106 , 0x10480 , 0x104AF , " Osmanya " } ,
{ 107 , 0x10800 , 0x1083F , " Cypriot Syllabary " } ,
{ 108 , 0x10A00 , 0x10A5F , " Kharoshthi " } ,
{ 109 , 0x1D300 , 0x1D35F , " Tai Xuan Jing Symbols " } ,
{ 110 , 0x12000 , 0x123FF , " Cuneiform " } ,
{ 110 , 0x12400 , 0x1247F , " Cuneiform Numbers and Punctuation " } ,
2011-01-21 19:44:33 +03:00
{ 111 , 0x1D360 , 0x1D37F , " Counting Rod Numerals " } ,
{ 112 , 0x1B80 , 0x1BBF , " Sundanese " } ,
{ 113 , 0x1C00 , 0x1C4F , " Lepcha " } ,
{ 114 , 0x1C50 , 0x1C7F , " Ol Chiki " } ,
{ 115 , 0xA880 , 0xA8DF , " Saurashtra " } ,
{ 116 , 0xA900 , 0xA92F , " Kayah Li " } ,
{ 117 , 0xA930 , 0xA95F , " Rejang " } ,
{ 118 , 0xAA00 , 0xAA5F , " Cham " } ,
{ 119 , 0x10190 , 0x101CF , " Ancient Symbols " } ,
{ 120 , 0x101D0 , 0x101FF , " Phaistos Disc " } ,
{ 121 , 0x10280 , 0x1029F , " Lycian " } ,
{ 121 , 0x102A0 , 0x102DF , " Carian " } ,
{ 121 , 0x10920 , 0x1093F , " Lydian " } ,
{ 122 , 0x1F000 , 0x1F02F , " Mahjong Tiles " } ,
{ 122 , 0x1F030 , 0x1F09F , " Domino Tiles " }
2007-12-28 04:28:26 +03:00
} ;
2010-06-11 23:14:38 +04:00
# pragma pack(1)
2007-12-28 04:28:26 +03:00
2010-06-11 23:14:38 +04:00
typedef struct {
AutoSwap_PRUint16 format ;
AutoSwap_PRUint16 reserved ;
AutoSwap_PRUint32 length ;
AutoSwap_PRUint32 language ;
AutoSwap_PRUint32 numGroups ;
} Format12CmapHeader ;
2007-12-28 04:28:26 +03:00
2010-06-11 23:14:38 +04:00
typedef struct {
AutoSwap_PRUint32 startCharCode ;
AutoSwap_PRUint32 endCharCode ;
AutoSwap_PRUint32 startGlyphId ;
} Format12Group ;
2007-12-28 04:28:26 +03:00
2010-06-11 23:14:38 +04:00
# pragma pack()
nsresult
gfxFontUtils : : ReadCMAPTableFormat12 ( const PRUint8 * aBuf , PRUint32 aLength ,
gfxSparseBitSet & aCharacterMap )
{
// Ensure table is large enough that we can safely read the header
NS_ENSURE_TRUE ( aLength > = sizeof ( Format12CmapHeader ) ,
NS_ERROR_GFX_CMAP_MALFORMED ) ;
// Sanity-check header fields
const Format12CmapHeader * cmap12 =
reinterpret_cast < const Format12CmapHeader * > ( aBuf ) ;
NS_ENSURE_TRUE ( PRUint16 ( cmap12 - > format ) = = 12 ,
2009-09-18 04:45:29 +04:00
NS_ERROR_GFX_CMAP_MALFORMED ) ;
2010-06-11 23:14:38 +04:00
NS_ENSURE_TRUE ( PRUint16 ( cmap12 - > reserved ) = = 0 ,
2009-09-18 04:45:29 +04:00
NS_ERROR_GFX_CMAP_MALFORMED ) ;
2007-12-28 04:28:26 +03:00
2010-06-11 23:14:38 +04:00
PRUint32 tablelen = cmap12 - > length ;
NS_ENSURE_TRUE ( tablelen > = sizeof ( Format12CmapHeader ) & &
tablelen < = aLength , NS_ERROR_GFX_CMAP_MALFORMED ) ;
2007-12-28 04:28:26 +03:00
2010-06-11 23:14:38 +04:00
NS_ENSURE_TRUE ( cmap12 - > language = = 0 , NS_ERROR_GFX_CMAP_MALFORMED ) ;
2007-12-28 04:28:26 +03:00
2010-06-11 23:14:38 +04:00
// Check that the table is large enough for the group array
const PRUint32 numGroups = cmap12 - > numGroups ;
NS_ENSURE_TRUE ( ( tablelen - sizeof ( Format12CmapHeader ) ) /
sizeof ( Format12Group ) > = numGroups ,
2009-09-18 04:45:29 +04:00
NS_ERROR_GFX_CMAP_MALFORMED ) ;
2007-12-28 04:28:26 +03:00
2010-06-11 23:14:38 +04:00
// The array of groups immediately follows the subtable header.
const Format12Group * group =
reinterpret_cast < const Format12Group * > ( aBuf + sizeof ( Format12CmapHeader ) ) ;
// Check that groups are in correct order and do not overlap,
// and record character coverage in aCharacterMap.
2009-09-18 04:45:29 +04:00
PRUint32 prevEndCharCode = 0 ;
2010-06-11 23:14:38 +04:00
for ( PRUint32 i = 0 ; i < numGroups ; i + + , group + + ) {
const PRUint32 startCharCode = group - > startCharCode ;
const PRUint32 endCharCode = group - > endCharCode ;
2009-09-18 04:45:29 +04:00
NS_ENSURE_TRUE ( ( prevEndCharCode < startCharCode | | i = = 0 ) & &
startCharCode < = endCharCode & &
endCharCode < = CMAP_MAX_CODEPOINT ,
NS_ERROR_GFX_CMAP_MALFORMED ) ;
2007-12-28 04:28:26 +03:00
aCharacterMap . SetRange ( startCharCode , endCharCode ) ;
2009-09-18 04:45:29 +04:00
prevEndCharCode = endCharCode ;
2007-12-28 04:28:26 +03:00
}
2010-04-15 12:31:12 +04:00
aCharacterMap . mBlocks . Compact ( ) ;
2007-12-28 04:28:26 +03:00
return NS_OK ;
}
nsresult
2010-06-11 23:14:38 +04:00
gfxFontUtils : : ReadCMAPTableFormat4 ( const PRUint8 * aBuf , PRUint32 aLength ,
gfxSparseBitSet & aCharacterMap )
2007-12-28 04:28:26 +03:00
{
enum {
OffsetFormat = 0 ,
OffsetLength = 2 ,
OffsetLanguage = 4 ,
OffsetSegCountX2 = 6
} ;
2009-09-18 04:45:29 +04:00
NS_ENSURE_TRUE ( ReadShortAt ( aBuf , OffsetFormat ) = = 4 ,
NS_ERROR_GFX_CMAP_MALFORMED ) ;
2007-12-28 04:28:26 +03:00
PRUint16 tablelen = ReadShortAt ( aBuf , OffsetLength ) ;
2009-09-18 04:45:29 +04:00
NS_ENSURE_TRUE ( tablelen < = aLength , NS_ERROR_GFX_CMAP_MALFORMED ) ;
NS_ENSURE_TRUE ( tablelen > 16 , NS_ERROR_GFX_CMAP_MALFORMED ) ;
2007-12-28 04:28:26 +03:00
2010-01-07 16:53:31 +03:00
// This field should normally (except for Mac platform subtables) be zero according to
// the OT spec, but some buggy fonts have lang = 1 (which would be English for MacOS).
// E.g. Arial Narrow Bold, v. 1.1 (Tiger), Arial Unicode MS (see bug 530614).
// So accept either zero or one here; the error should be harmless.
NS_ENSURE_TRUE ( ( ReadShortAt ( aBuf , OffsetLanguage ) & 0xfffe ) = = 0 ,
2009-09-18 04:45:29 +04:00
NS_ERROR_GFX_CMAP_MALFORMED ) ;
2007-12-28 04:28:26 +03:00
PRUint16 segCountX2 = ReadShortAt ( aBuf , OffsetSegCountX2 ) ;
2009-09-18 04:45:29 +04:00
NS_ENSURE_TRUE ( tablelen > = 16 + ( segCountX2 * 4 ) ,
NS_ERROR_GFX_CMAP_MALFORMED ) ;
2007-12-28 04:28:26 +03:00
const PRUint16 segCount = segCountX2 / 2 ;
2009-08-16 17:52:12 +04:00
const PRUint16 * endCounts = reinterpret_cast < const PRUint16 * > ( aBuf + 14 ) ;
2007-12-28 04:28:26 +03:00
const PRUint16 * startCounts = endCounts + 1 /* skip one uint16 for reservedPad */ + segCount ;
const PRUint16 * idDeltas = startCounts + segCount ;
const PRUint16 * idRangeOffsets = idDeltas + segCount ;
2009-09-18 04:45:29 +04:00
PRUint16 prevEndCount = 0 ;
2007-12-28 04:28:26 +03:00
for ( PRUint16 i = 0 ; i < segCount ; i + + ) {
const PRUint16 endCount = ReadShortAt16 ( endCounts , i ) ;
const PRUint16 startCount = ReadShortAt16 ( startCounts , i ) ;
const PRUint16 idRangeOffset = ReadShortAt16 ( idRangeOffsets , i ) ;
2009-12-22 12:47:18 +03:00
2009-09-18 04:45:29 +04:00
// sanity-check range
2009-12-22 12:47:18 +03:00
NS_ENSURE_TRUE ( ( startCount > prevEndCount | | i = = 0 | | startCount = = 0xFFFF ) & &
2009-09-18 04:45:29 +04:00
startCount < = endCount ,
NS_ERROR_GFX_CMAP_MALFORMED ) ;
prevEndCount = endCount ;
2009-12-22 12:47:18 +03:00
2007-12-28 04:28:26 +03:00
if ( idRangeOffset = = 0 ) {
aCharacterMap . SetRange ( startCount , endCount ) ;
} else {
2008-09-15 17:46:07 +04:00
// const PRUint16 idDelta = ReadShortAt16(idDeltas, i); // Unused: self-documenting.
2007-12-28 04:28:26 +03:00
for ( PRUint32 c = startCount ; c < = endCount ; + + c ) {
if ( c = = 0xFFFF )
break ;
const PRUint16 * gdata = ( idRangeOffset / 2
+ ( c - startCount )
+ & idRangeOffsets [ i ] ) ;
2009-09-18 04:45:29 +04:00
NS_ENSURE_TRUE ( ( PRUint8 * ) gdata > aBuf & &
( PRUint8 * ) gdata < aBuf + aLength ,
NS_ERROR_GFX_CMAP_MALFORMED ) ;
2007-12-28 04:28:26 +03:00
// make sure we have a glyph
if ( * gdata ! = 0 ) {
// The glyph index at this point is:
// glyph = (ReadShortAt16(idDeltas, i) + *gdata) % 65536;
aCharacterMap . set ( c ) ;
}
}
}
}
2010-04-15 12:31:12 +04:00
aCharacterMap . mBlocks . Compact ( ) ;
2007-12-28 04:28:26 +03:00
return NS_OK ;
}
2010-06-01 17:42:37 +04:00
nsresult
2010-06-11 23:14:38 +04:00
gfxFontUtils : : ReadCMAPTableFormat14 ( const PRUint8 * aBuf , PRUint32 aLength ,
2010-06-01 17:42:37 +04:00
PRUint8 * & aTable )
{
enum {
OffsetFormat = 0 ,
OffsetTableLength = 2 ,
OffsetNumVarSelectorRecords = 6 ,
OffsetVarSelectorRecords = 10 ,
SizeOfVarSelectorRecord = 11 ,
VSRecOffsetVarSelector = 0 ,
VSRecOffsetDefUVSOffset = 3 ,
VSRecOffsetNonDefUVSOffset = 7 ,
SizeOfDefUVSTable = 4 ,
DefUVSOffsetStartUnicodeValue = 0 ,
DefUVSOffsetAdditionalCount = 3 ,
SizeOfNonDefUVSTable = 5 ,
NonDefUVSOffsetUnicodeValue = 0 ,
NonDefUVSOffsetGlyphID = 3
} ;
NS_ENSURE_TRUE ( aLength > = OffsetVarSelectorRecords ,
NS_ERROR_GFX_CMAP_MALFORMED ) ;
NS_ENSURE_TRUE ( ReadShortAt ( aBuf , OffsetFormat ) = = 14 ,
NS_ERROR_GFX_CMAP_MALFORMED ) ;
PRUint32 tablelen = ReadLongAt ( aBuf , OffsetTableLength ) ;
NS_ENSURE_TRUE ( tablelen < = aLength , NS_ERROR_GFX_CMAP_MALFORMED ) ;
NS_ENSURE_TRUE ( tablelen > = OffsetVarSelectorRecords ,
NS_ERROR_GFX_CMAP_MALFORMED ) ;
const PRUint32 numVarSelectorRecords = ReadLongAt ( aBuf , OffsetNumVarSelectorRecords ) ;
NS_ENSURE_TRUE ( ( tablelen - OffsetVarSelectorRecords ) /
SizeOfVarSelectorRecord > = numVarSelectorRecords ,
NS_ERROR_GFX_CMAP_MALFORMED ) ;
const PRUint8 * records = aBuf + OffsetVarSelectorRecords ;
for ( PRUint32 i = 0 ; i < numVarSelectorRecords ;
i + + , records + = SizeOfVarSelectorRecord ) {
const PRUint32 varSelector = ReadUint24At ( records , VSRecOffsetVarSelector ) ;
const PRUint32 defUVSOffset = ReadLongAt ( records , VSRecOffsetDefUVSOffset ) ;
const PRUint32 nonDefUVSOffset = ReadLongAt ( records , VSRecOffsetNonDefUVSOffset ) ;
NS_ENSURE_TRUE ( varSelector < = CMAP_MAX_CODEPOINT & &
defUVSOffset < = tablelen - 4 & &
nonDefUVSOffset < = tablelen - 4 ,
NS_ERROR_GFX_CMAP_MALFORMED ) ;
if ( defUVSOffset ) {
const PRUint32 numUnicodeValueRanges = ReadLongAt ( aBuf , defUVSOffset ) ;
NS_ENSURE_TRUE ( ( tablelen - defUVSOffset ) /
SizeOfDefUVSTable > = numUnicodeValueRanges ,
NS_ERROR_GFX_CMAP_MALFORMED ) ;
const PRUint8 * tables = aBuf + defUVSOffset + 4 ;
PRUint32 prevEndUnicode = 0 ;
for ( PRUint32 j = 0 ; j < numUnicodeValueRanges ; j + + , tables + = SizeOfDefUVSTable ) {
const PRUint32 startUnicode = ReadUint24At ( tables , DefUVSOffsetStartUnicodeValue ) ;
const PRUint32 endUnicode = startUnicode + tables [ DefUVSOffsetAdditionalCount ] ;
NS_ENSURE_TRUE ( ( prevEndUnicode < startUnicode | | j = = 0 ) & &
endUnicode < = CMAP_MAX_CODEPOINT ,
NS_ERROR_GFX_CMAP_MALFORMED ) ;
prevEndUnicode = endUnicode ;
}
}
if ( nonDefUVSOffset ) {
const PRUint32 numUVSMappings = ReadLongAt ( aBuf , nonDefUVSOffset ) ;
NS_ENSURE_TRUE ( ( tablelen - nonDefUVSOffset ) /
SizeOfNonDefUVSTable > = numUVSMappings ,
NS_ERROR_GFX_CMAP_MALFORMED ) ;
const PRUint8 * tables = aBuf + nonDefUVSOffset + 4 ;
PRUint32 prevUnicode = 0 ;
for ( PRUint32 j = 0 ; j < numUVSMappings ; j + + , tables + = SizeOfNonDefUVSTable ) {
const PRUint32 unicodeValue = ReadUint24At ( tables , NonDefUVSOffsetUnicodeValue ) ;
NS_ENSURE_TRUE ( ( prevUnicode < unicodeValue | | j = = 0 ) & &
unicodeValue < = CMAP_MAX_CODEPOINT ,
NS_ERROR_GFX_CMAP_MALFORMED ) ;
prevUnicode = unicodeValue ;
}
}
}
aTable = new PRUint8 [ tablelen ] ;
memcpy ( aTable , aBuf , tablelen ) ;
return NS_OK ;
}
2007-12-28 04:28:26 +03:00
// Windows requires fonts to have a format-4 cmap with a Microsoft ID (3). On the Mac, fonts either have
// a format-4 cmap with Microsoft platform/encoding id or they have one with a platformID == Unicode (0)
2010-05-16 14:53:43 +04:00
// For fonts with two format-4 tables, the first one (Unicode platform) is preferred on the Mac.
2007-12-28 04:28:26 +03:00
# if defined(XP_MACOSX)
2010-06-01 17:42:37 +04:00
# define acceptableFormat4(p,e,k) (((p) == PLATFORM_ID_MICROSOFT && (e) == EncodingIDMicrosoft && !(k)) || \
( ( p ) = = PLATFORM_ID_UNICODE ) )
# define acceptableUCS4Encoding(p, e, k) \
( ( ( p ) = = PLATFORM_ID_MICROSOFT & & ( e ) = = EncodingIDUCS4ForMicrosoftPlatform ) & & ( k ) ! = 12 | | \
( ( p ) = = PLATFORM_ID_UNICODE & & \
( ( e ) = = EncodingIDDefaultForUnicodePlatform | | ( e ) > = EncodingIDUCS4ForUnicodePlatform ) ) )
2007-12-28 04:28:26 +03:00
# else
2010-06-01 17:42:37 +04:00
# define acceptableFormat4(p,e,k) ((p) == PLATFORM_ID_MICROSOFT && (e) == EncodingIDMicrosoft)
# define acceptableUCS4Encoding(p, e, k) \
( ( p ) = = PLATFORM_ID_MICROSOFT & & ( e ) = = EncodingIDUCS4ForMicrosoftPlatform )
2007-12-28 04:28:26 +03:00
# endif
2010-06-01 17:42:37 +04:00
# define acceptablePlatform(p) ((p) == PLATFORM_ID_UNICODE || (p) == PLATFORM_ID_MICROSOFT)
# define isSymbol(p,e) ((p) == PLATFORM_ID_MICROSOFT && (e) == EncodingIDSymbol)
# define isUVSEncoding(p, e) ((p) == PLATFORM_ID_UNICODE && (e) == EncodingIDUVSForUnicodePlatform)
2008-03-14 11:35:35 +03:00
2009-12-10 23:18:14 +03:00
PRUint32
2010-06-11 23:14:38 +04:00
gfxFontUtils : : FindPreferredSubtable ( const PRUint8 * aBuf , PRUint32 aBufLength ,
PRUint32 * aTableOffset ,
PRUint32 * aUVSTableOffset ,
2010-06-01 17:42:37 +04:00
PRBool * aSymbolEncoding )
2007-12-28 04:28:26 +03:00
{
enum {
OffsetVersion = 0 ,
OffsetNumTables = 2 ,
SizeOfHeader = 4 ,
TableOffsetPlatformID = 0 ,
TableOffsetEncodingID = 2 ,
TableOffsetOffset = 4 ,
SizeOfTable = 8 ,
SubtableOffsetFormat = 0
} ;
enum {
EncodingIDSymbol = 0 ,
EncodingIDMicrosoft = 1 ,
2009-12-10 23:18:23 +03:00
EncodingIDDefaultForUnicodePlatform = 0 ,
2008-03-14 11:35:35 +03:00
EncodingIDUCS4ForUnicodePlatform = 3 ,
2010-06-01 17:42:37 +04:00
EncodingIDUVSForUnicodePlatform = 5 ,
2008-03-14 11:35:35 +03:00
EncodingIDUCS4ForMicrosoftPlatform = 10
2007-12-28 04:28:26 +03:00
} ;
2010-06-01 17:42:37 +04:00
if ( aUVSTableOffset ) {
* aUVSTableOffset = nsnull ;
}
2010-09-03 14:45:53 +04:00
if ( ! aBuf | | aBufLength < SizeOfHeader ) {
// cmap table is missing, or too small to contain header fields!
return 0 ;
}
2008-09-15 17:46:07 +04:00
// PRUint16 version = ReadShortAt(aBuf, OffsetVersion); // Unused: self-documenting.
2007-12-28 04:28:26 +03:00
PRUint16 numTables = ReadShortAt ( aBuf , OffsetNumTables ) ;
2010-12-05 21:38:12 +03:00
if ( aBufLength < PRUint32 ( SizeOfHeader + numTables * SizeOfTable ) ) {
2010-09-03 14:45:53 +04:00
return 0 ;
}
2007-12-28 04:28:26 +03:00
2009-12-10 23:18:14 +03:00
// save the format we want here
2007-12-28 04:28:26 +03:00
PRUint32 keepFormat = 0 ;
2010-06-11 23:14:38 +04:00
const PRUint8 * table = aBuf + SizeOfHeader ;
2007-12-28 04:28:26 +03:00
for ( PRUint16 i = 0 ; i < numTables ; + + i , table + = SizeOfTable ) {
const PRUint16 platformID = ReadShortAt ( table , TableOffsetPlatformID ) ;
if ( ! acceptablePlatform ( platformID ) )
continue ;
const PRUint16 encodingID = ReadShortAt ( table , TableOffsetEncodingID ) ;
const PRUint32 offset = ReadLongAt ( table , TableOffsetOffset ) ;
2010-09-03 14:45:53 +04:00
if ( aBufLength - 2 < offset ) {
// this subtable is not valid - beyond end of buffer
return 0 ;
}
2008-01-30 01:12:11 +03:00
2007-12-28 04:28:26 +03:00
const PRUint8 * subtable = aBuf + offset ;
const PRUint16 format = ReadShortAt ( subtable , SubtableOffsetFormat ) ;
if ( isSymbol ( platformID , encodingID ) ) {
keepFormat = format ;
2009-12-10 23:18:14 +03:00
* aTableOffset = offset ;
* aSymbolEncoding = PR_TRUE ;
2007-12-28 04:28:26 +03:00
break ;
2010-05-16 14:53:43 +04:00
} else if ( format = = 4 & & acceptableFormat4 ( platformID , encodingID , keepFormat ) ) {
2007-12-28 04:28:26 +03:00
keepFormat = format ;
2009-12-10 23:18:14 +03:00
* aTableOffset = offset ;
* aSymbolEncoding = PR_FALSE ;
2010-06-01 17:42:37 +04:00
} else if ( format = = 12 & & acceptableUCS4Encoding ( platformID , encodingID , keepFormat ) ) {
2007-12-28 04:28:26 +03:00
keepFormat = format ;
2009-12-10 23:18:14 +03:00
* aTableOffset = offset ;
* aSymbolEncoding = PR_FALSE ;
2010-06-01 17:42:37 +04:00
if ( platformID > PLATFORM_ID_UNICODE | | ! aUVSTableOffset | | * aUVSTableOffset ) {
break ; // we don't want to try anything else when this format is available.
}
} else if ( format = = 14 & & isUVSEncoding ( platformID , encodingID ) & & aUVSTableOffset ) {
* aUVSTableOffset = offset ;
if ( keepFormat = = 12 ) {
break ;
}
2007-12-28 04:28:26 +03:00
}
}
2009-12-10 23:18:14 +03:00
return keepFormat ;
}
nsresult
2010-06-11 23:14:38 +04:00
gfxFontUtils : : ReadCMAP ( const PRUint8 * aBuf , PRUint32 aBufLength ,
gfxSparseBitSet & aCharacterMap ,
2010-06-01 17:42:37 +04:00
PRUint32 & aUVSOffset ,
2009-12-10 23:18:14 +03:00
PRPackedBool & aUnicodeFont , PRPackedBool & aSymbolFont )
{
PRUint32 offset ;
PRBool symbol ;
2010-06-11 23:14:38 +04:00
PRUint32 format = FindPreferredSubtable ( aBuf , aBufLength ,
& offset , & aUVSOffset , & symbol ) ;
2009-12-10 23:18:14 +03:00
if ( format = = 4 ) {
if ( symbol ) {
aUnicodeFont = PR_FALSE ;
aSymbolFont = PR_TRUE ;
} else {
aUnicodeFont = PR_TRUE ;
aSymbolFont = PR_FALSE ;
}
2010-06-11 23:14:38 +04:00
return ReadCMAPTableFormat4 ( aBuf + offset , aBufLength - offset ,
aCharacterMap ) ;
2009-12-10 23:18:14 +03:00
}
2007-12-28 04:28:26 +03:00
2009-12-10 23:18:14 +03:00
if ( format = = 12 ) {
aUnicodeFont = PR_TRUE ;
aSymbolFont = PR_FALSE ;
2010-06-11 23:14:38 +04:00
return ReadCMAPTableFormat12 ( aBuf + offset , aBufLength - offset ,
aCharacterMap ) ;
2009-12-10 23:18:14 +03:00
}
2007-12-28 04:28:26 +03:00
2009-12-10 23:18:14 +03:00
return NS_ERROR_FAILURE ;
}
# pragma pack(1)
typedef struct {
AutoSwap_PRUint16 format ;
AutoSwap_PRUint16 length ;
AutoSwap_PRUint16 language ;
AutoSwap_PRUint16 segCountX2 ;
AutoSwap_PRUint16 searchRange ;
AutoSwap_PRUint16 entrySelector ;
AutoSwap_PRUint16 rangeShift ;
AutoSwap_PRUint16 arrays [ 1 ] ;
} Format4Cmap ;
2010-04-22 22:51:11 +04:00
2010-06-01 17:42:37 +04:00
typedef struct {
AutoSwap_PRUint16 format ;
AutoSwap_PRUint32 length ;
AutoSwap_PRUint32 numVarSelectorRecords ;
typedef struct {
AutoSwap_PRUint24 varSelector ;
AutoSwap_PRUint32 defaultUVSOffset ;
AutoSwap_PRUint32 nonDefaultUVSOffset ;
} VarSelectorRecord ;
VarSelectorRecord varSelectorRecords [ 1 ] ;
} Format14Cmap ;
typedef struct {
AutoSwap_PRUint32 numUVSMappings ;
typedef struct {
AutoSwap_PRUint24 unicodeValue ;
AutoSwap_PRUint16 glyphID ;
} UVSMapping ;
UVSMapping uvsMappings [ 1 ] ;
} NonDefUVSTable ;
2010-04-24 12:25:45 +04:00
# pragma pack()
2009-12-10 23:18:14 +03:00
PRUint32
gfxFontUtils : : MapCharToGlyphFormat4 ( const PRUint8 * aBuf , PRUnichar aCh )
{
const Format4Cmap * cmap4 = reinterpret_cast < const Format4Cmap * > ( aBuf ) ;
PRUint16 segCount ;
const AutoSwap_PRUint16 * endCodes ;
const AutoSwap_PRUint16 * startCodes ;
const AutoSwap_PRUint16 * idDelta ;
const AutoSwap_PRUint16 * idRangeOffset ;
PRUint16 probe ;
PRUint16 rangeShiftOver2 ;
PRUint16 index ;
segCount = ( PRUint16 ) ( cmap4 - > segCountX2 ) / 2 ;
endCodes = & cmap4 - > arrays [ 0 ] ;
startCodes = & cmap4 - > arrays [ segCount + 1 ] ; // +1 for reserved word between arrays
idDelta = & startCodes [ segCount ] ;
idRangeOffset = & idDelta [ segCount ] ;
probe = 1 < < ( PRUint16 ) ( cmap4 - > entrySelector ) ;
rangeShiftOver2 = ( PRUint16 ) ( cmap4 - > rangeShift ) / 2 ;
if ( ( PRUint16 ) ( startCodes [ rangeShiftOver2 ] ) < = aCh ) {
index = rangeShiftOver2 ;
} else {
index = 0 ;
}
while ( probe > 1 ) {
probe > > = 1 ;
if ( ( PRUint16 ) ( startCodes [ index + probe ] ) < = aCh ) {
index + = probe ;
}
}
if ( aCh > = ( PRUint16 ) ( startCodes [ index ] ) & & aCh < = ( PRUint16 ) ( endCodes [ index ] ) ) {
PRUint16 result ;
if ( ( PRUint16 ) ( idRangeOffset [ index ] ) = = 0 ) {
result = aCh ;
} else {
PRUint16 offset = aCh - ( PRUint16 ) ( startCodes [ index ] ) ;
const AutoSwap_PRUint16 * glyphIndexTable =
( const AutoSwap_PRUint16 * ) ( ( const char * ) & idRangeOffset [ index ] +
( PRUint16 ) ( idRangeOffset [ index ] ) ) ;
result = glyphIndexTable [ offset ] ;
}
// note that this is unsigned 16-bit arithmetic, and may wrap around
result + = ( PRUint16 ) ( idDelta [ index ] ) ;
return result ;
}
return 0 ;
}
2010-06-11 23:14:38 +04:00
PRUint32
gfxFontUtils : : MapCharToGlyphFormat12 ( const PRUint8 * aBuf , PRUint32 aCh )
{
const Format12CmapHeader * cmap12 =
reinterpret_cast < const Format12CmapHeader * > ( aBuf ) ;
// We know that numGroups is within range for the subtable size
// because it was checked by ReadCMAPTableFormat12.
PRUint32 numGroups = cmap12 - > numGroups ;
// The array of groups immediately follows the subtable header.
const Format12Group * groups =
reinterpret_cast < const Format12Group * > ( aBuf + sizeof ( Format12CmapHeader ) ) ;
// For most efficient binary search, we want to work on a range that
// is a power of 2 so that we can always halve it by shifting.
// So we find the largest power of 2 that is <= numGroups.
// We will offset this range by rangeOffset so as to reach the end
// of the table, provided that doesn't put us beyond the target
// value from the outset.
PRUint32 powerOf2 = mozilla : : FindHighestBit ( numGroups ) ;
PRUint32 rangeOffset = numGroups - powerOf2 ;
PRUint32 range = 0 ;
PRUint32 startCharCode ;
if ( groups [ rangeOffset ] . startCharCode < = aCh ) {
range = rangeOffset ;
}
// Repeatedly halve the size of the range until we find the target group
while ( powerOf2 > 1 ) {
powerOf2 > > = 1 ;
if ( groups [ range + powerOf2 ] . startCharCode < = aCh ) {
range + = powerOf2 ;
}
}
// Check if the character is actually present in the range and return
// the corresponding glyph ID
startCharCode = groups [ range ] . startCharCode ;
if ( startCharCode < = aCh & & groups [ range ] . endCharCode > = aCh ) {
return groups [ range ] . startGlyphId + aCh - startCharCode ;
}
// Else it's not present, so return the .notdef glyph
return 0 ;
}
2010-06-01 17:42:37 +04:00
PRUint16
gfxFontUtils : : MapUVSToGlyphFormat14 ( const PRUint8 * aBuf , PRUint32 aCh , PRUint32 aVS )
{
const Format14Cmap * cmap14 = reinterpret_cast < const Format14Cmap * > ( aBuf ) ;
// binary search in varSelectorRecords
PRUint32 min = 0 ;
PRUint32 max = cmap14 - > numVarSelectorRecords ;
PRUint32 nonDefUVSOffset = 0 ;
while ( min < max ) {
PRUint32 index = ( min + max ) > > 1 ;
PRUint32 varSelector = cmap14 - > varSelectorRecords [ index ] . varSelector ;
if ( aVS = = varSelector ) {
nonDefUVSOffset = cmap14 - > varSelectorRecords [ index ] . nonDefaultUVSOffset ;
break ;
}
if ( aVS < varSelector ) {
max = index ;
} else {
min = index + 1 ;
}
}
if ( ! nonDefUVSOffset ) {
return 0 ;
}
const NonDefUVSTable * table = reinterpret_cast < const NonDefUVSTable * >
( aBuf + nonDefUVSOffset ) ;
// binary search in uvsMappings
min = 0 ;
max = table - > numUVSMappings ;
while ( min < max ) {
PRUint32 index = ( min + max ) > > 1 ;
PRUint32 unicodeValue = table - > uvsMappings [ index ] . unicodeValue ;
if ( aCh = = unicodeValue ) {
return table - > uvsMappings [ index ] . glyphID ;
}
if ( aCh < unicodeValue ) {
max = index ;
} else {
min = index + 1 ;
}
}
return 0 ;
}
2009-12-10 23:18:14 +03:00
PRUint32
2010-06-11 23:14:38 +04:00
gfxFontUtils : : MapCharToGlyph ( const PRUint8 * aBuf , PRUint32 aBufLength ,
2010-07-28 08:00:38 +04:00
PRUint32 aCh )
2009-12-10 23:18:14 +03:00
{
PRUint32 offset ;
PRBool symbol ;
2010-06-11 23:14:38 +04:00
PRUint32 format = FindPreferredSubtable ( aBuf , aBufLength , & offset ,
nsnull , & symbol ) ;
switch ( format ) {
case 4 :
return aCh < UNICODE_BMP_LIMIT ?
2010-07-28 08:00:38 +04:00
MapCharToGlyphFormat4 ( aBuf + offset , PRUnichar ( aCh ) ) : 0 ;
2010-06-11 23:14:38 +04:00
case 12 :
return MapCharToGlyphFormat12 ( aBuf + offset , aCh ) ;
default :
return 0 ;
}
2007-12-28 04:28:26 +03:00
}
PRUint8 gfxFontUtils : : CharRangeBit ( PRUint32 ch ) {
const PRUint32 n = sizeof ( gUnicodeRanges ) / sizeof ( struct UnicodeRangeTableEntry ) ;
for ( PRUint32 i = 0 ; i < n ; + + i )
if ( ch > = gUnicodeRanges [ i ] . start & & ch < = gUnicodeRanges [ i ] . end )
return gUnicodeRanges [ i ] . bit ;
return NO_RANGE_FOUND ;
}
2008-04-18 08:32:18 +04:00
void gfxFontUtils : : GetPrefsFontList ( const char * aPrefName , nsTArray < nsString > & aFontList )
2008-02-26 11:00:44 +03:00
{
const PRUnichar kComma = PRUnichar ( ' , ' ) ;
aFontList . Clear ( ) ;
// get the list of single-face font families
2011-06-12 06:30:16 +04:00
nsAdoptingString fontlistValue = Preferences : : GetString ( aPrefName ) ;
if ( ! fontlistValue ) {
return ;
2008-02-26 11:00:44 +03:00
}
2011-06-12 06:30:16 +04:00
2008-02-26 11:00:44 +03:00
// append each font name to the list
nsAutoString fontname ;
const PRUnichar * p , * p_end ;
2011-06-14 06:02:35 +04:00
fontlistValue . BeginReading ( p ) ;
fontlistValue . EndReading ( p_end ) ;
2008-02-26 11:00:44 +03:00
while ( p < p_end ) {
const PRUnichar * nameStart = p ;
while ( + + p ! = p_end & & * p ! = kComma )
/* nothing */ ;
// pull out a single name and clean out leading/trailing whitespace
fontname = Substring ( nameStart , p ) ;
fontname . CompressWhitespace ( PR_TRUE , PR_TRUE ) ;
// append it to the list
aFontList . AppendElement ( fontname ) ;
+ + p ;
}
}
2009-03-11 04:00:44 +03:00
// produce a unique font name that is (1) a valid Postscript name and (2) less
// than 31 characters in length. Using AddFontMemResourceEx on Windows fails
// for names longer than 30 characters in length.
# define MAX_B64_LEN 32
nsresult gfxFontUtils : : MakeUniqueUserFontName ( nsAString & aName )
{
nsCOMPtr < nsIUUIDGenerator > uuidgen =
do_GetService ( " @mozilla.org/uuid-generator;1 " ) ;
NS_ENSURE_TRUE ( uuidgen , NS_ERROR_OUT_OF_MEMORY ) ;
nsID guid ;
NS_ASSERTION ( sizeof ( guid ) * 2 < = MAX_B64_LEN , " size of nsID has changed! " ) ;
nsresult rv = uuidgen - > GenerateUUIDInPlace ( & guid ) ;
NS_ENSURE_SUCCESS ( rv , rv ) ;
char guidB64 [ MAX_B64_LEN ] = { 0 } ;
2009-08-16 17:52:12 +04:00
if ( ! PL_Base64Encode ( reinterpret_cast < char * > ( & guid ) , sizeof ( guid ) , guidB64 ) )
2009-03-11 04:00:44 +03:00
return NS_ERROR_FAILURE ;
// all b64 characters except for '/' are allowed in Postscript names, so convert / ==> -
char * p ;
for ( p = guidB64 ; * p ; p + + ) {
if ( * p = = ' / ' )
* p = ' - ' ;
}
aName . Assign ( NS_LITERAL_STRING ( " uf " ) ) ;
aName . AppendASCII ( guidB64 ) ;
return NS_OK ;
}
2008-10-01 07:01:53 +04:00
// TrueType/OpenType table handling code
// need byte aligned structs
# pragma pack(1)
2008-10-29 21:09:50 +03:00
// name table stores set of name record structures, followed by
// large block containing all the strings. name record offset and length
// indicates the offset and length within that block.
// http://www.microsoft.com/typography/otspec/name.htm
struct NameRecordData {
PRUint32 offset ;
PRUint32 length ;
} ;
2010-04-24 12:25:45 +04:00
# pragma pack()
2008-10-29 21:09:50 +03:00
static PRBool
IsValidSFNTVersion ( PRUint32 version )
{
// normally 0x00010000, CFF-style OT fonts == 'OTTO' and Apple TT fonts = 'true'
// 'typ1' is also possible for old Type 1 fonts in a SFNT container but not supported
2009-08-16 17:52:12 +04:00
return version = = 0x10000 | |
version = = TRUETYPE_TAG ( ' O ' , ' T ' , ' T ' , ' O ' ) | |
version = = TRUETYPE_TAG ( ' t ' , ' r ' , ' u ' , ' e ' ) ;
2008-10-29 21:09:50 +03:00
}
// copy and swap UTF-16 values, assume no surrogate pairs, can be in place
static void
CopySwapUTF16 ( const PRUint16 * aInBuf , PRUint16 * aOutBuf , PRUint32 aLen )
{
const PRUint16 * end = aInBuf + aLen ;
while ( aInBuf < end ) {
PRUint16 value = * aInBuf ;
* aOutBuf = ( value > > 8 ) | ( value & 0xff ) < < 8 ;
aOutBuf + + ;
aInBuf + + ;
}
}
2009-04-14 12:48:32 +04:00
static PRBool
ValidateKernTable ( const PRUint8 * aKernTable , PRUint32 aKernLength )
{
// -- kern table can cause crashes if invalid, so do some basic sanity-checking
const KernTableVersion0 * kernTable0 = reinterpret_cast < const KernTableVersion0 * > ( aKernTable ) ;
if ( aKernLength < sizeof ( KernTableVersion0 ) ) {
return PR_FALSE ;
}
if ( PRUint16 ( kernTable0 - > version ) = = 0 ) {
if ( aKernLength < sizeof ( KernTableVersion0 ) +
PRUint16 ( kernTable0 - > nTables ) * sizeof ( KernTableSubtableHeaderVersion0 ) ) {
return PR_FALSE ;
}
// at least the table is big enough to contain the subtable headers;
// we could go further and check the actual subtable sizes....
// for now, assume this is OK
return PR_TRUE ;
}
const KernTableVersion1 * kernTable1 = reinterpret_cast < const KernTableVersion1 * > ( aKernTable ) ;
if ( aKernLength < sizeof ( KernTableVersion1 ) ) {
return PR_FALSE ;
}
if ( kernTable1 - > version = = 0x00010000 ) {
if ( aKernLength < sizeof ( KernTableVersion1 ) +
kernTable1 - > nTables * sizeof ( KernTableSubtableHeaderVersion1 ) ) {
return PR_FALSE ;
}
// at least the table is big enough to contain the subtable headers;
// we could go further and check the actual subtable sizes....
// for now, assume this is OK
return PR_TRUE ;
}
// neither the old Windows version nor the newer Apple one; refuse to use it
return PR_FALSE ;
}
2010-07-22 13:25:23 +04:00
static PRBool
ValidateLocaTable ( const PRUint8 * aLocaTable , PRUint32 aLocaLen ,
PRUint32 aGlyfLen , PRInt16 aLocaFormat , PRUint16 aNumGlyphs )
{
if ( aLocaFormat = = 0 ) {
if ( aLocaLen < PRUint32 ( aNumGlyphs + 1 ) * sizeof ( PRUint16 ) ) {
return PR_FALSE ;
}
const AutoSwap_PRUint16 * p =
reinterpret_cast < const AutoSwap_PRUint16 * > ( aLocaTable ) ;
PRUint32 prev = 0 ;
for ( PRUint32 i = 0 ; i < = aNumGlyphs ; + + i ) {
PRUint32 current = PRUint16 ( * p + + ) * 2 ;
if ( current < prev | | current > aGlyfLen ) {
return PR_FALSE ;
}
prev = current ;
}
return PR_TRUE ;
}
if ( aLocaFormat = = 1 ) {
if ( aLocaLen < ( aNumGlyphs + 1 ) * sizeof ( PRUint32 ) ) {
return PR_FALSE ;
}
const AutoSwap_PRUint32 * p =
reinterpret_cast < const AutoSwap_PRUint32 * > ( aLocaTable ) ;
PRUint32 prev = 0 ;
for ( PRUint32 i = 0 ; i < = aNumGlyphs ; + + i ) {
PRUint32 current = * p + + ;
if ( current < prev | | current > aGlyfLen ) {
return PR_FALSE ;
}
prev = current ;
}
return PR_TRUE ;
}
return PR_FALSE ;
}
2009-08-30 17:55:24 +04:00
gfxUserFontType
gfxFontUtils : : DetermineFontDataType ( const PRUint8 * aFontData , PRUint32 aFontDataLength )
{
// test for OpenType font data
// problem: EOT-Lite with 0x10000 length will look like TrueType!
if ( aFontDataLength > = sizeof ( SFNTHeader ) ) {
const SFNTHeader * sfntHeader = reinterpret_cast < const SFNTHeader * > ( aFontData ) ;
PRUint32 sfntVersion = sfntHeader - > sfntVersion ;
if ( IsValidSFNTVersion ( sfntVersion ) ) {
return GFX_USERFONT_OPENTYPE ;
}
}
// test for WOFF
if ( aFontDataLength > = sizeof ( AutoSwap_PRUint32 ) ) {
const AutoSwap_PRUint32 * version =
reinterpret_cast < const AutoSwap_PRUint32 * > ( aFontData ) ;
if ( PRUint32 ( * version ) = = TRUETYPE_TAG ( ' w ' , ' O ' , ' F ' , ' F ' ) ) {
return GFX_USERFONT_WOFF ;
}
}
// tests for other formats here
return GFX_USERFONT_UNKNOWN ;
}
2008-10-29 21:09:50 +03:00
PRBool
2008-12-22 08:01:14 +03:00
gfxFontUtils : : ValidateSFNTHeaders ( const PRUint8 * aFontData ,
2009-08-30 17:55:24 +04:00
PRUint32 aFontDataLength )
2008-10-29 21:09:50 +03:00
{
2009-08-30 17:55:24 +04:00
NS_ASSERTION ( aFontData , " null font data " ) ;
2008-10-29 21:09:50 +03:00
PRUint64 dataLength ( aFontDataLength ) ;
// read in the sfnt header
if ( sizeof ( SFNTHeader ) > aFontDataLength ) {
NS_WARNING ( " invalid font (insufficient data) " ) ;
return PR_FALSE ;
}
const SFNTHeader * sfntHeader = reinterpret_cast < const SFNTHeader * > ( aFontData ) ;
PRUint32 sfntVersion = sfntHeader - > sfntVersion ;
if ( ! IsValidSFNTVersion ( sfntVersion ) ) {
NS_WARNING ( " invalid font (SFNT version) " ) ;
return PR_FALSE ;
}
2008-12-22 08:01:14 +03:00
2008-10-29 21:09:50 +03:00
// iterate through the table headers to find the head, name and OS/2 tables
PRBool foundHead = PR_FALSE , foundOS2 = PR_FALSE , foundName = PR_FALSE ;
2009-04-14 12:48:32 +04:00
PRBool foundGlyphs = PR_FALSE , foundCFF = PR_FALSE , foundKern = PR_FALSE ;
2010-07-22 13:25:23 +04:00
PRBool foundLoca = PR_FALSE , foundMaxp = PR_FALSE ;
2010-12-05 21:38:12 +03:00
PRUint32 headOffset = 0 , headLen , nameOffset = 0 , nameLen , kernOffset = 0 ,
kernLen = 0 , glyfLen = 0 , locaOffset = 0 , locaLen = 0 ,
maxpOffset = 0 , maxpLen ;
2008-10-29 21:09:50 +03:00
PRUint32 i , numTables ;
numTables = sfntHeader - > numTables ;
PRUint32 headerLen = sizeof ( SFNTHeader ) + sizeof ( TableDirEntry ) * numTables ;
if ( headerLen > aFontDataLength ) {
NS_WARNING ( " invalid font (table directory) " ) ;
return PR_FALSE ;
}
// table directory entries begin immediately following SFNT header
2008-12-22 08:01:14 +03:00
const TableDirEntry * dirEntry =
reinterpret_cast < const TableDirEntry * > ( aFontData + sizeof ( SFNTHeader ) ) ;
2008-10-29 21:09:50 +03:00
PRUint32 checksum = 0 ;
// checksum for font = (checksum of header) + (checksum of tables)
2008-12-22 08:01:14 +03:00
const AutoSwap_PRUint32 * headerData =
reinterpret_cast < const AutoSwap_PRUint32 * > ( aFontData ) ;
2008-10-29 21:09:50 +03:00
// header length is in bytes, checksum calculated in longwords
for ( i = 0 ; i < ( headerLen > > 2 ) ; i + + , headerData + + ) {
checksum + = * headerData ;
}
for ( i = 0 ; i < numTables ; i + + , dirEntry + + ) {
// sanity check on offset, length values
if ( PRUint64 ( dirEntry - > offset ) + PRUint64 ( dirEntry - > length ) > dataLength ) {
NS_WARNING ( " invalid font (table directory entry) " ) ;
return PR_FALSE ;
}
checksum + = dirEntry - > checkSum ;
switch ( dirEntry - > tag ) {
2009-04-02 12:06:33 +04:00
case TRUETYPE_TAG ( ' h ' , ' e ' , ' a ' , ' d ' ) :
2008-10-29 21:09:50 +03:00
foundHead = PR_TRUE ;
headOffset = dirEntry - > offset ;
headLen = dirEntry - > length ;
if ( headLen < sizeof ( HeadTable ) ) {
NS_WARNING ( " invalid font (head table length) " ) ;
return PR_FALSE ;
}
break ;
2009-04-14 12:48:32 +04:00
case TRUETYPE_TAG ( ' k ' , ' e ' , ' r ' , ' n ' ) :
foundKern = PR_TRUE ;
kernOffset = dirEntry - > offset ;
kernLen = dirEntry - > length ;
break ;
2009-04-02 12:06:33 +04:00
case TRUETYPE_TAG ( ' n ' , ' a ' , ' m ' , ' e ' ) :
2008-10-29 21:09:50 +03:00
foundName = PR_TRUE ;
nameOffset = dirEntry - > offset ;
nameLen = dirEntry - > length ;
break ;
2009-04-02 12:06:33 +04:00
case TRUETYPE_TAG ( ' O ' , ' S ' , ' / ' , ' 2 ' ) :
2008-10-29 21:09:50 +03:00
foundOS2 = PR_TRUE ;
break ;
2009-04-02 12:06:33 +04:00
case TRUETYPE_TAG ( ' g ' , ' l ' , ' y ' , ' f ' ) : // TrueType-style quadratic glyph table
2008-10-29 21:09:50 +03:00
foundGlyphs = PR_TRUE ;
2010-07-22 13:25:23 +04:00
glyfLen = dirEntry - > length ;
break ;
case TRUETYPE_TAG ( ' l ' , ' o ' , ' c ' , ' a ' ) : // glyph location table
foundLoca = PR_TRUE ;
locaOffset = dirEntry - > offset ;
locaLen = dirEntry - > length ;
break ;
case TRUETYPE_TAG ( ' m ' , ' a ' , ' x ' , ' p ' ) : // max profile
foundMaxp = PR_TRUE ;
maxpOffset = dirEntry - > offset ;
maxpLen = dirEntry - > length ;
if ( maxpLen < sizeof ( MaxpTableHeader ) ) {
NS_WARNING ( " invalid font (maxp table length) " ) ;
return PR_FALSE ;
}
2008-10-29 21:09:50 +03:00
break ;
2009-04-02 12:06:33 +04:00
case TRUETYPE_TAG ( ' C ' , ' F ' , ' F ' , ' ' ) : // PS-style cubic glyph table
2008-10-29 21:09:50 +03:00
foundCFF = PR_TRUE ;
break ;
default :
break ;
}
}
// simple sanity checks
2010-07-22 13:25:23 +04:00
// -- fonts need head, name, maxp tables
if ( ! foundHead | | ! foundName | | ! foundMaxp ) {
NS_WARNING ( " invalid font (missing head/name/maxp table) " ) ;
2008-10-29 21:09:50 +03:00
return PR_FALSE ;
}
// -- on Windows need OS/2 table
# ifdef XP_WIN
if ( ! foundOS2 ) {
NS_WARNING ( " invalid font (missing OS/2 table) " ) ;
return PR_FALSE ;
}
# endif
// -- head table data
const HeadTable * headData = reinterpret_cast < const HeadTable * > ( aFontData + headOffset ) ;
2010-08-17 18:49:40 +04:00
if ( headData - > tableVersionNumber ! = HeadTable : : HEAD_VERSION ) {
NS_WARNING ( " invalid font (head table version) " ) ;
return PR_FALSE ;
}
2008-10-29 21:09:50 +03:00
if ( headData - > magicNumber ! = HeadTable : : HEAD_MAGIC_NUMBER ) {
NS_WARNING ( " invalid font (head magic number) " ) ;
return PR_FALSE ;
}
if ( headData - > checkSumAdjustment ! = ( HeadTable : : HEAD_CHECKSUM_CALC_CONST - checksum ) ) {
NS_WARNING ( " invalid font (bad checksum) " ) ;
2009-05-20 11:17:28 +04:00
// Bug 483459 - warn about a bad checksum but allow the font to be
// used, since a small percentage of fonts don't calculate this
// correctly and font systems aren't fussy about this
// return PR_FALSE;
2008-10-29 21:09:50 +03:00
}
// need glyf or CFF table based on sfnt version
2009-04-02 12:06:33 +04:00
if ( sfntVersion = = TRUETYPE_TAG ( ' O ' , ' T ' , ' T ' , ' O ' ) ) {
2008-10-29 21:09:50 +03:00
if ( ! foundCFF ) {
NS_WARNING ( " invalid font (missing CFF table) " ) ;
return PR_FALSE ;
}
} else {
2010-07-22 13:25:23 +04:00
if ( ! foundGlyphs | | ! foundLoca ) {
NS_WARNING ( " invalid font (missing glyf or loca table) " ) ;
return PR_FALSE ;
}
// sanity-check 'loca' offsets
const MaxpTableHeader * maxpData =
reinterpret_cast < const MaxpTableHeader * > ( aFontData + maxpOffset ) ;
if ( ! ValidateLocaTable ( aFontData + locaOffset , locaLen , glyfLen ,
headData - > indexToLocFormat ,
maxpData - > numGlyphs ) ) {
NS_WARNING ( " invalid font (loca table offsets) " ) ;
2008-10-29 21:09:50 +03:00
return PR_FALSE ;
}
}
// -- name table data
const NameHeader * nameHeader = reinterpret_cast < const NameHeader * > ( aFontData + nameOffset ) ;
PRUint32 nameCount = nameHeader - > count ;
// -- sanity check the number of name records
if ( PRUint64 ( nameCount ) * sizeof ( NameRecord ) + PRUint64 ( nameOffset ) > dataLength ) {
NS_WARNING ( " invalid font (name records) " ) ;
return PR_FALSE ;
}
// -- iterate through name records
2009-08-16 17:52:12 +04:00
const NameRecord * nameRecord = reinterpret_cast < const NameRecord * >
( aFontData + nameOffset + sizeof ( NameHeader ) ) ;
2008-10-29 21:09:50 +03:00
PRUint64 nameStringsBase = PRUint64 ( nameOffset ) + PRUint64 ( nameHeader - > stringOffset ) ;
for ( i = 0 ; i < nameCount ; i + + , nameRecord + + ) {
PRUint32 namelen = nameRecord - > length ;
PRUint32 nameoff = nameRecord - > offset ; // offset from base of string storage
if ( nameStringsBase + PRUint64 ( nameoff ) + PRUint64 ( namelen ) > dataLength ) {
NS_WARNING ( " invalid font (name table strings) " ) ;
return PR_FALSE ;
}
}
2009-04-14 12:48:32 +04:00
// -- sanity-check the kern table, if present (see bug 487549)
if ( foundKern ) {
if ( ! ValidateKernTable ( aFontData + kernOffset , kernLen ) ) {
NS_WARNING ( " invalid font (kern table) " ) ;
return PR_FALSE ;
}
}
2008-10-29 21:09:50 +03:00
// everything seems consistent
return PR_TRUE ;
}
2008-12-22 08:01:14 +03:00
nsresult
gfxFontUtils : : RenameFont ( const nsAString & aName , const PRUint8 * aFontData ,
2011-01-07 07:45:10 +03:00
PRUint32 aFontDataLength , FallibleTArray < PRUint8 > * aNewFont )
2008-12-22 08:01:14 +03:00
{
NS_ASSERTION ( aNewFont , " null font data array " ) ;
PRUint64 dataLength ( aFontDataLength ) ;
// new name table
2009-08-16 17:52:12 +04:00
static const PRUint32 neededNameIDs [ ] = { NAME_ID_FAMILY ,
NAME_ID_STYLE ,
NAME_ID_UNIQUE ,
NAME_ID_FULL ,
NAME_ID_POSTSCRIPT } ;
2008-12-22 08:01:14 +03:00
// calculate new name table size
PRUint16 nameCount = NS_ARRAY_LENGTH ( neededNameIDs ) ;
// leave room for null-terminator
PRUint16 nameStrLength = ( aName . Length ( ) + 1 ) * sizeof ( PRUnichar ) ;
// round name table size up to 4-byte multiple
PRUint32 nameTableSize = ( sizeof ( NameHeader ) +
sizeof ( NameRecord ) * nameCount +
nameStrLength +
3 ) & ~ 3 ;
if ( dataLength + nameTableSize > PR_UINT32_MAX )
return NS_ERROR_FAILURE ;
2009-09-18 06:39:22 +04:00
// bug 505386 - need to handle unpadded font length
PRUint32 paddedFontDataSize = ( aFontDataLength + 3 ) & ~ 3 ;
PRUint32 adjFontDataSize = paddedFontDataSize + nameTableSize ;
2008-12-22 08:01:14 +03:00
// create new buffer: old font data plus new name table
if ( ! aNewFont - > AppendElements ( adjFontDataSize ) )
return NS_ERROR_OUT_OF_MEMORY ;
// copy the old font data
PRUint8 * newFontData = reinterpret_cast < PRUint8 * > ( aNewFont - > Elements ( ) ) ;
2009-09-18 06:39:22 +04:00
// null the last four bytes in case the font length is not a multiple of 4
memset ( newFontData + aFontDataLength , 0 , paddedFontDataSize - aFontDataLength ) ;
// copy font data
2008-12-22 08:01:14 +03:00
memcpy ( newFontData , aFontData , aFontDataLength ) ;
// null out the last 4 bytes for checksum calculations
memset ( newFontData + adjFontDataSize - 4 , 0 , 4 ) ;
NameHeader * nameHeader = reinterpret_cast < NameHeader * > ( newFontData +
2009-09-18 06:39:22 +04:00
paddedFontDataSize ) ;
2008-12-22 08:01:14 +03:00
// -- name header
nameHeader - > format = 0 ;
nameHeader - > count = nameCount ;
nameHeader - > stringOffset = sizeof ( NameHeader ) + nameCount * sizeof ( NameRecord ) ;
// -- name records
PRUint32 i ;
NameRecord * nameRecord = reinterpret_cast < NameRecord * > ( nameHeader + 1 ) ;
for ( i = 0 ; i < nameCount ; i + + , nameRecord + + ) {
2009-08-16 17:52:12 +04:00
nameRecord - > platformID = PLATFORM_ID_MICROSOFT ;
nameRecord - > encodingID = ENCODING_ID_MICROSOFT_UNICODEBMP ;
nameRecord - > languageID = LANG_ID_MICROSOFT_EN_US ;
2008-12-22 08:01:14 +03:00
nameRecord - > nameID = neededNameIDs [ i ] ;
nameRecord - > offset = 0 ;
nameRecord - > length = nameStrLength ;
}
// -- string data, located after the name records, stored in big-endian form
PRUnichar * strData = reinterpret_cast < PRUnichar * > ( nameRecord ) ;
const PRUnichar * nameStr = aName . BeginReading ( ) ;
const PRUnichar * nameStrEnd = aName . EndReading ( ) ;
while ( nameStr < nameStrEnd ) {
PRUnichar ch = * nameStr + + ;
* strData + + = NS_SWAP16 ( ch ) ;
}
* strData = 0 ; // add null termination
// adjust name table header to point to the new name table
SFNTHeader * sfntHeader = reinterpret_cast < SFNTHeader * > ( newFontData ) ;
// table directory entries begin immediately following SFNT header
TableDirEntry * dirEntry =
reinterpret_cast < TableDirEntry * > ( newFontData + sizeof ( SFNTHeader ) ) ;
PRUint32 numTables = sfntHeader - > numTables ;
PRBool foundName = PR_FALSE ;
for ( i = 0 ; i < numTables ; i + + , dirEntry + + ) {
2009-04-02 12:06:33 +04:00
if ( dirEntry - > tag = = TRUETYPE_TAG ( ' n ' , ' a ' , ' m ' , ' e ' ) ) {
2008-12-22 08:01:14 +03:00
foundName = PR_TRUE ;
break ;
}
}
// function only called if font validates, so this should always be true
NS_ASSERTION ( foundName , " attempt to rename font with no name table " ) ;
// note: dirEntry now points to name record
// recalculate name table checksum
PRUint32 checkSum = 0 ;
AutoSwap_PRUint32 * nameData = reinterpret_cast < AutoSwap_PRUint32 * > ( nameHeader ) ;
AutoSwap_PRUint32 * nameDataEnd = nameData + ( nameTableSize > > 2 ) ;
while ( nameData < nameDataEnd )
checkSum = checkSum + * nameData + + ;
// adjust name table entry to point to new name table
2009-09-18 06:39:22 +04:00
dirEntry - > offset = paddedFontDataSize ;
2008-12-22 08:01:14 +03:00
dirEntry - > length = nameTableSize ;
dirEntry - > checkSum = checkSum ;
// fix up checksums
PRUint32 checksum = 0 ;
// checksum for font = (checksum of header) + (checksum of tables)
PRUint32 headerLen = sizeof ( SFNTHeader ) + sizeof ( TableDirEntry ) * numTables ;
const AutoSwap_PRUint32 * headerData =
reinterpret_cast < const AutoSwap_PRUint32 * > ( newFontData ) ;
// header length is in bytes, checksum calculated in longwords
for ( i = 0 ; i < ( headerLen > > 2 ) ; i + + , headerData + + ) {
checksum + = * headerData ;
}
PRUint32 headOffset = 0 ;
dirEntry = reinterpret_cast < TableDirEntry * > ( newFontData + sizeof ( SFNTHeader ) ) ;
for ( i = 0 ; i < numTables ; i + + , dirEntry + + ) {
2009-04-02 12:06:33 +04:00
if ( dirEntry - > tag = = TRUETYPE_TAG ( ' h ' , ' e ' , ' a ' , ' d ' ) ) {
2008-12-22 08:01:14 +03:00
headOffset = dirEntry - > offset ;
}
checksum + = dirEntry - > checkSum ;
}
NS_ASSERTION ( headOffset ! = 0 , " no head table for font " ) ;
HeadTable * headData = reinterpret_cast < HeadTable * > ( newFontData + headOffset ) ;
headData - > checkSumAdjustment = HeadTable : : HEAD_CHECKSUM_CALC_CONST - checksum ;
return NS_OK ;
}
2009-04-02 12:06:33 +04:00
enum {
# if defined(XP_MACOSX)
2009-08-16 17:52:12 +04:00
CANONICAL_LANG_ID = gfxFontUtils : : LANG_ID_MAC_ENGLISH ,
PLATFORM_ID = gfxFontUtils : : PLATFORM_ID_MAC
2009-04-02 12:06:33 +04:00
# else
2009-08-16 17:52:12 +04:00
CANONICAL_LANG_ID = gfxFontUtils : : LANG_ID_MICROSOFT_EN_US ,
PLATFORM_ID = gfxFontUtils : : PLATFORM_ID_MICROSOFT
2009-04-02 12:06:33 +04:00
# endif
} ;
nsresult
2011-01-07 07:45:10 +03:00
gfxFontUtils : : ReadNames ( FallibleTArray < PRUint8 > & aNameTable , PRUint32 aNameID ,
2009-04-02 12:06:33 +04:00
PRInt32 aPlatformID , nsTArray < nsString > & aNames )
{
2009-08-16 17:52:12 +04:00
return ReadNames ( aNameTable , aNameID , LANG_ALL , aPlatformID , aNames ) ;
2009-04-02 12:06:33 +04:00
}
nsresult
2011-01-07 07:45:10 +03:00
gfxFontUtils : : ReadCanonicalName ( FallibleTArray < PRUint8 > & aNameTable , PRUint32 aNameID ,
2009-04-02 12:06:33 +04:00
nsString & aName )
{
nsresult rv ;
nsTArray < nsString > names ;
// first, look for the English name (this will succeed 99% of the time)
rv = ReadNames ( aNameTable , aNameID , CANONICAL_LANG_ID , PLATFORM_ID , names ) ;
NS_ENSURE_SUCCESS ( rv , rv ) ;
// otherwise, grab names for all languages
if ( names . Length ( ) = = 0 ) {
2009-08-16 17:52:12 +04:00
rv = ReadNames ( aNameTable , aNameID , LANG_ALL , PLATFORM_ID , names ) ;
2009-04-02 12:06:33 +04:00
NS_ENSURE_SUCCESS ( rv , rv ) ;
}
# if defined(XP_MACOSX)
// may be dealing with font that only has Microsoft name entries
if ( names . Length ( ) = = 0 ) {
2009-08-16 17:52:12 +04:00
rv = ReadNames ( aNameTable , aNameID , LANG_ID_MICROSOFT_EN_US ,
PLATFORM_ID_MICROSOFT , names ) ;
2009-04-02 12:06:33 +04:00
NS_ENSURE_SUCCESS ( rv , rv ) ;
// getting really desperate now, take anything!
if ( names . Length ( ) = = 0 ) {
2009-08-16 17:52:12 +04:00
rv = ReadNames ( aNameTable , aNameID , LANG_ALL ,
PLATFORM_ID_MICROSOFT , names ) ;
2009-04-02 12:06:33 +04:00
NS_ENSURE_SUCCESS ( rv , rv ) ;
}
}
# endif
// return the first name (99.9% of the time names will
// contain a single English name)
if ( names . Length ( ) ) {
aName . Assign ( names [ 0 ] ) ;
return NS_OK ;
}
return NS_ERROR_FAILURE ;
}
2009-08-16 17:52:12 +04:00
// Charsets to use for decoding Mac platform font names.
// This table is sorted by {encoding, language}, with the wildcard "ANY" being
// greater than any defined values for each field; we use a binary search on both
// fields, and fall back to matching only encoding if necessary
// Some "redundant" entries for specific combinations are included such as
// encoding=roman, lang=english, in order that common entries will be found
// on the first search.
# define ANY 0xffff
const gfxFontUtils : : MacFontNameCharsetMapping gfxFontUtils : : gMacFontNameCharsets [ ] =
2009-04-02 12:06:33 +04:00
{
2009-08-16 17:52:12 +04:00
{ ENCODING_ID_MAC_ROMAN , LANG_ID_MAC_ENGLISH , " x-mac-roman " } ,
{ ENCODING_ID_MAC_ROMAN , LANG_ID_MAC_ICELANDIC , " x-mac-icelandic " } ,
{ ENCODING_ID_MAC_ROMAN , LANG_ID_MAC_TURKISH , " x-mac-turkish " } ,
{ ENCODING_ID_MAC_ROMAN , LANG_ID_MAC_POLISH , " x-mac-ce " } ,
{ ENCODING_ID_MAC_ROMAN , LANG_ID_MAC_ROMANIAN , " x-mac-romanian " } ,
{ ENCODING_ID_MAC_ROMAN , LANG_ID_MAC_CZECH , " x-mac-ce " } ,
{ ENCODING_ID_MAC_ROMAN , LANG_ID_MAC_SLOVAK , " x-mac-ce " } ,
{ ENCODING_ID_MAC_ROMAN , ANY , " x-mac-roman " } ,
{ ENCODING_ID_MAC_JAPANESE , LANG_ID_MAC_JAPANESE , " Shift_JIS " } ,
{ ENCODING_ID_MAC_JAPANESE , ANY , " Shift_JIS " } ,
{ ENCODING_ID_MAC_TRAD_CHINESE , LANG_ID_MAC_TRAD_CHINESE , " Big5 " } ,
{ ENCODING_ID_MAC_TRAD_CHINESE , ANY , " Big5 " } ,
{ ENCODING_ID_MAC_KOREAN , LANG_ID_MAC_KOREAN , " EUC-KR " } ,
{ ENCODING_ID_MAC_KOREAN , ANY , " EUC-KR " } ,
{ ENCODING_ID_MAC_ARABIC , LANG_ID_MAC_ARABIC , " x-mac-arabic " } ,
{ ENCODING_ID_MAC_ARABIC , LANG_ID_MAC_URDU , " x-mac-farsi " } ,
{ ENCODING_ID_MAC_ARABIC , LANG_ID_MAC_FARSI , " x-mac-farsi " } ,
{ ENCODING_ID_MAC_ARABIC , ANY , " x-mac-arabic " } ,
{ ENCODING_ID_MAC_HEBREW , LANG_ID_MAC_HEBREW , " x-mac-hebrew " } ,
{ ENCODING_ID_MAC_HEBREW , ANY , " x-mac-hebrew " } ,
{ ENCODING_ID_MAC_GREEK , ANY , " x-mac-greek " } ,
{ ENCODING_ID_MAC_CYRILLIC , ANY , " x-mac-cyrillic " } ,
{ ENCODING_ID_MAC_DEVANAGARI , ANY , " x-mac-devanagari " } ,
{ ENCODING_ID_MAC_GURMUKHI , ANY , " x-mac-gurmukhi " } ,
{ ENCODING_ID_MAC_GUJARATI , ANY , " x-mac-gujarati " } ,
{ ENCODING_ID_MAC_SIMP_CHINESE , LANG_ID_MAC_SIMP_CHINESE , " GB2312 " } ,
{ ENCODING_ID_MAC_SIMP_CHINESE , ANY , " GB2312 " }
} ;
2009-04-02 12:06:33 +04:00
2009-08-16 17:52:12 +04:00
const char * gfxFontUtils : : gISOFontNameCharsets [ ] =
{
/* 0 */ " us-ascii " ,
/* 1 */ nsnull , /* spec says "ISO 10646" but does not specify encoding form! */
/* 2 */ " ISO-8859-1 "
} ;
2009-04-02 12:06:33 +04:00
2009-08-16 17:52:12 +04:00
const char * gfxFontUtils : : gMSFontNameCharsets [ ] =
{
/* [0] ENCODING_ID_MICROSOFT_SYMBOL */ " " ,
/* [1] ENCODING_ID_MICROSOFT_UNICODEBMP */ " " ,
/* [2] ENCODING_ID_MICROSOFT_SHIFTJIS */ " Shift_JIS " ,
/* [3] ENCODING_ID_MICROSOFT_PRC */ nsnull ,
/* [4] ENCODING_ID_MICROSOFT_BIG5 */ " Big5 " ,
/* [5] ENCODING_ID_MICROSOFT_WANSUNG */ nsnull ,
/* [6] ENCODING_ID_MICROSOFT_JOHAB */ " x-johab " ,
/* [7] reserved */ nsnull ,
/* [8] reserved */ nsnull ,
/* [9] reserved */ nsnull ,
/*[10] ENCODING_ID_MICROSOFT_UNICODEFULL */ " "
} ;
# define ARRAY_SIZE(A) (sizeof(A) / sizeof(A[0]))
// Return the name of the charset we should use to decode a font name
// given the name table attributes.
// Special return values:
// "" charset is UTF16BE, no need for a converter
// nsnull unknown charset, do not attempt conversion
const char *
gfxFontUtils : : GetCharsetForFontName ( PRUint16 aPlatform , PRUint16 aScript , PRUint16 aLanguage )
{
switch ( aPlatform )
2009-04-02 12:06:33 +04:00
{
2009-08-16 17:52:12 +04:00
case PLATFORM_ID_UNICODE :
return " " ;
case PLATFORM_ID_MAC :
{
PRUint32 lo = 0 , hi = ARRAY_SIZE ( gMacFontNameCharsets ) ;
MacFontNameCharsetMapping searchValue = { aScript , aLanguage , nsnull } ;
for ( PRUint32 i = 0 ; i < 2 ; + + i ) {
// binary search; if not found, set language to ANY and try again
while ( lo < hi ) {
PRUint32 mid = ( lo + hi ) / 2 ;
const MacFontNameCharsetMapping & entry = gMacFontNameCharsets [ mid ] ;
if ( entry < searchValue ) {
lo = mid + 1 ;
continue ;
}
if ( searchValue < entry ) {
hi = mid ;
continue ;
}
// found a match
return entry . mCharsetName ;
}
// no match, so reset high bound for search and re-try
hi = ARRAY_SIZE ( gMacFontNameCharsets ) ;
searchValue . mLanguage = ANY ;
}
}
break ;
case PLATFORM_ID_ISO :
if ( aScript < ARRAY_SIZE ( gISOFontNameCharsets ) ) {
return gISOFontNameCharsets [ aScript ] ;
}
break ;
case PLATFORM_ID_MICROSOFT :
if ( aScript < ARRAY_SIZE ( gMSFontNameCharsets ) ) {
return gMSFontNameCharsets [ aScript ] ;
}
break ;
2009-04-02 12:06:33 +04:00
}
2009-08-16 17:52:12 +04:00
return nsnull ;
}
2009-04-02 12:06:33 +04:00
2009-08-16 17:52:12 +04:00
// convert a raw name from the name table to an nsString, if possible;
// return value indicates whether conversion succeeded
PRBool
gfxFontUtils : : DecodeFontName ( const PRUint8 * aNameData , PRInt32 aByteLen ,
PRUint32 aPlatformCode , PRUint32 aScriptCode ,
PRUint32 aLangCode , nsAString & aName )
{
NS_ASSERTION ( aByteLen > 0 , " bad length for font name data " ) ;
const char * csName = GetCharsetForFontName ( aPlatformCode , aScriptCode , aLangCode ) ;
if ( ! csName ) {
// nsnull -> unknown charset
# ifdef DEBUG
char warnBuf [ 128 ] ;
if ( aByteLen > 64 )
aByteLen = 64 ;
sprintf ( warnBuf , " skipping font name, unknown charset %d:%d:%d for <%.*s> " ,
aPlatformCode , aScriptCode , aLangCode , aByteLen , aNameData ) ;
NS_WARNING ( warnBuf ) ;
# endif
return PR_FALSE ;
}
2009-04-02 12:06:33 +04:00
2009-08-16 17:52:12 +04:00
if ( csName [ 0 ] = = 0 ) {
// empty charset name: data is utf16be, no need to instantiate a converter
PRUint32 strLen = aByteLen / 2 ;
2009-04-02 12:06:33 +04:00
# ifdef IS_LITTLE_ENDIAN
2009-08-16 17:52:12 +04:00
aName . SetLength ( strLen ) ;
2009-08-18 12:26:20 +04:00
CopySwapUTF16 ( reinterpret_cast < const PRUint16 * > ( aNameData ) ,
reinterpret_cast < PRUint16 * > ( aName . BeginWriting ( ) ) , strLen ) ;
2009-04-02 12:06:33 +04:00
# else
2009-08-16 17:52:12 +04:00
aName . Assign ( reinterpret_cast < const PRUnichar * > ( aNameData ) , strLen ) ;
2009-04-02 12:06:33 +04:00
# endif
2009-08-16 17:52:12 +04:00
return PR_TRUE ;
}
2009-04-02 12:06:33 +04:00
2009-08-16 17:52:12 +04:00
nsresult rv ;
nsCOMPtr < nsICharsetConverterManager > ccm =
do_GetService ( NS_CHARSETCONVERTERMANAGER_CONTRACTID , & rv ) ;
NS_ASSERTION ( NS_SUCCEEDED ( rv ) , " failed to get charset converter manager " ) ;
if ( NS_FAILED ( rv ) ) {
return PR_FALSE ;
}
2009-04-02 12:06:33 +04:00
2009-08-16 17:52:12 +04:00
nsCOMPtr < nsIUnicodeDecoder > decoder ;
2010-11-08 13:27:40 +03:00
rv = ccm - > GetUnicodeDecoderRawInternal ( csName , getter_AddRefs ( decoder ) ) ;
2009-08-16 17:52:12 +04:00
if ( NS_FAILED ( rv ) ) {
NS_WARNING ( " failed to get the decoder for a font name string " ) ;
return PR_FALSE ;
}
PRInt32 destLength ;
rv = decoder - > GetMaxLength ( reinterpret_cast < const char * > ( aNameData ) , aByteLen , & destLength ) ;
if ( NS_FAILED ( rv ) ) {
NS_WARNING ( " decoder->GetMaxLength failed, invalid font name? " ) ;
return PR_FALSE ;
}
// make space for the converted string
aName . SetLength ( destLength ) ;
rv = decoder - > Convert ( reinterpret_cast < const char * > ( aNameData ) , & aByteLen ,
aName . BeginWriting ( ) , & destLength ) ;
if ( NS_FAILED ( rv ) ) {
NS_WARNING ( " decoder->Convert failed, invalid font name? " ) ;
return PR_FALSE ;
}
aName . Truncate ( destLength ) ; // set the actual length
return PR_TRUE ;
2009-04-02 12:06:33 +04:00
}
nsresult
2011-01-07 07:45:10 +03:00
gfxFontUtils : : ReadNames ( FallibleTArray < PRUint8 > & aNameTable , PRUint32 aNameID ,
2009-04-02 12:06:33 +04:00
PRInt32 aLangID , PRInt32 aPlatformID ,
nsTArray < nsString > & aNames )
{
PRUint32 nameTableLen = aNameTable . Length ( ) ;
NS_ASSERTION ( nameTableLen ! = 0 , " null name table " ) ;
if ( nameTableLen = = 0 )
return NS_ERROR_FAILURE ;
PRUint8 * nameTable = aNameTable . Elements ( ) ;
// -- name table data
const NameHeader * nameHeader = reinterpret_cast < const NameHeader * > ( nameTable ) ;
PRUint32 nameCount = nameHeader - > count ;
// -- sanity check the number of name records
if ( PRUint64 ( nameCount ) * sizeof ( NameRecord ) > nameTableLen ) {
NS_WARNING ( " invalid font (name table data) " ) ;
return NS_ERROR_FAILURE ;
}
// -- iterate through name records
const NameRecord * nameRecord
= reinterpret_cast < const NameRecord * > ( nameTable + sizeof ( NameHeader ) ) ;
PRUint64 nameStringsBase = PRUint64 ( nameHeader - > stringOffset ) ;
PRUint32 i ;
for ( i = 0 ; i < nameCount ; i + + , nameRecord + + ) {
PRUint32 platformID ;
// skip over unwanted nameID's
if ( PRUint32 ( nameRecord - > nameID ) ! = aNameID )
continue ;
// skip over unwanted platform data
platformID = nameRecord - > platformID ;
if ( aPlatformID ! = PLATFORM_ALL
& & PRUint32 ( nameRecord - > platformID ) ! = PLATFORM_ID )
continue ;
// skip over unwanted languages
2009-08-16 17:52:12 +04:00
if ( aLangID ! = LANG_ALL
2009-04-02 12:06:33 +04:00
& & PRUint32 ( nameRecord - > languageID ) ! = PRUint32 ( aLangID ) )
continue ;
// add name to names array
// -- calculate string location
PRUint32 namelen = nameRecord - > length ;
PRUint32 nameoff = nameRecord - > offset ; // offset from base of string storage
if ( nameStringsBase + PRUint64 ( nameoff ) + PRUint64 ( namelen )
> nameTableLen ) {
NS_WARNING ( " invalid font (name table strings) " ) ;
return NS_ERROR_FAILURE ;
}
// -- decode if necessary and make nsString
nsAutoString name ;
nsresult rv ;
2009-08-16 17:52:12 +04:00
rv = DecodeFontName ( nameTable + nameStringsBase + nameoff , namelen ,
platformID , PRUint32 ( nameRecord - > encodingID ) ,
PRUint32 ( nameRecord - > languageID ) , name ) ;
2009-04-02 12:06:33 +04:00
if ( NS_FAILED ( rv ) )
continue ;
PRUint32 k , numNames ;
PRBool foundName = PR_FALSE ;
numNames = aNames . Length ( ) ;
for ( k = 0 ; k < numNames ; k + + ) {
if ( name . Equals ( aNames [ k ] ) ) {
foundName = PR_TRUE ;
break ;
}
}
if ( ! foundName )
aNames . AppendElement ( name ) ;
}
return NS_OK ;
}
2010-04-24 12:25:45 +04:00
# ifdef XP_WIN
2008-10-01 07:01:53 +04:00
// Embedded OpenType (EOT) handling
// needed for dealing with downloadable fonts on Windows
//
// EOT version 0x00020001
// based on http://www.w3.org/Submission/2008/SUBM-EOT-20080305/
//
// EOT header consists of a fixed-size portion containing general font
// info, followed by a variable-sized portion containing name data,
// followed by the actual TT/OT font data (non-byte values are always
// stored in big-endian format)
//
// EOT header is stored in *little* endian order!!
2010-04-24 12:25:45 +04:00
# pragma pack(1)
2008-10-01 07:01:53 +04:00
struct EOTFixedHeader {
PRUint32 eotSize ; // Total structure length in PRUint8s (including string and font data)
PRUint32 fontDataSize ; // Length of the OpenType font (FontData) in PRUint8s
PRUint32 version ; // Version number of this format - 0x00010000
PRUint32 flags ; // Processing Flags
PRUint8 panose [ 10 ] ; // The PANOSE value for this font - See http://www.microsoft.com/typography/otspec/os2.htm#pan
PRUint8 charset ; // In Windows this is derived from TEXTMETRIC.tmCharSet. This value specifies the character set of the font. DEFAULT_CHARSET (0x01) indicates no preference. - See http://msdn2.microsoft.com/en-us/library/ms534202.aspx
PRUint8 italic ; // If the bit for ITALIC is set in OS/2.fsSelection, the value will be 0x01 - See http://www.microsoft.com/typography/otspec/os2.htm#fss
PRUint32 weight ; // The weight value for this font - See http://www.microsoft.com/typography/otspec/os2.htm#wtc
PRUint16 fsType ; // Type flags that provide information about embedding permissions - See http://www.microsoft.com/typography/otspec/os2.htm#fst
PRUint16 magicNumber ; // Magic number for EOT file - 0x504C. Used to check for data corruption.
PRUint32 unicodeRange1 ; // OS/2.UnicodeRange1 (bits 0-31) - See http://www.microsoft.com/typography/otspec/os2.htm#ur
PRUint32 unicodeRange2 ; // OS/2.UnicodeRange2 (bits 32-63) - See http://www.microsoft.com/typography/otspec/os2.htm#ur
PRUint32 unicodeRange3 ; // OS/2.UnicodeRange3 (bits 64-95) - See http://www.microsoft.com/typography/otspec/os2.htm#ur
PRUint32 unicodeRange4 ; // OS/2.UnicodeRange4 (bits 96-127) - See http://www.microsoft.com/typography/otspec/os2.htm#ur
PRUint32 codePageRange1 ; // CodePageRange1 (bits 0-31) - See http://www.microsoft.com/typography/otspec/os2.htm#cpr
PRUint32 codePageRange2 ; // CodePageRange2 (bits 32-63) - See http://www.microsoft.com/typography/otspec/os2.htm#cpr
PRUint32 checkSumAdjustment ; // head.CheckSumAdjustment - See http://www.microsoft.com/typography/otspec/head.htm
PRUint32 reserved [ 4 ] ; // Reserved - must be 0
PRUint16 padding1 ; // Padding to maintain long alignment. Padding value must always be set to 0x0000.
enum {
EOT_VERSION = 0x00020001 ,
EOT_MAGIC_NUMBER = 0x504c ,
EOT_DEFAULT_CHARSET = 0x01 ,
EOT_EMBED_PRINT_PREVIEW = 0x0004 ,
EOT_FAMILY_NAME_INDEX = 0 , // order of names in variable portion of EOT header
EOT_STYLE_NAME_INDEX = 1 ,
EOT_VERSION_NAME_INDEX = 2 ,
EOT_FULL_NAME_INDEX = 3 ,
EOT_NUM_NAMES = 4
} ;
} ;
2010-04-24 12:25:45 +04:00
# pragma pack()
2008-10-29 21:09:50 +03:00
2010-04-24 12:25:45 +04:00
// EOT headers are only used on Windows
2008-10-29 21:09:50 +03:00
2008-10-01 07:01:53 +04:00
// EOT variable-sized header (version 0x00020001 - contains 4 name
// fields, each with the structure):
//
// // number of bytes in the name array
// PRUint16 size;
// // array of UTF-16 chars, total length = <size> bytes
// // note: english version of name record string
// PRUint8 name[size];
//
// This structure is used for the following names, each separated by two
// bytes of padding (always 0 with no padding after the rootString):
//
// familyName - based on name ID = 1
// styleName - based on name ID = 2
// versionName - based on name ID = 5
// fullName - based on name ID = 4
// rootString - used to restrict font usage to a specific domain
//
# if DEBUG
2008-10-29 21:09:50 +03:00
static void
DumpEOTHeader ( PRUint8 * aHeader , PRUint32 aHeaderLen )
2008-10-01 07:01:53 +04:00
{
PRUint32 offset = 0 ;
PRUint8 * ch = aHeader ;
printf ( " \n \n len == %d \n \n " , aHeaderLen ) ;
while ( offset < aHeaderLen ) {
printf ( " %7.7x " , offset ) ;
int i ;
for ( i = 0 ; i < 16 ; i + + ) {
printf ( " %2.2x " , * ch + + ) ;
}
printf ( " \n " ) ;
offset + = 16 ;
}
}
# endif
nsresult
2008-10-29 21:09:50 +03:00
gfxFontUtils : : MakeEOTHeader ( const PRUint8 * aFontData , PRUint32 aFontDataLength ,
2011-01-07 07:45:10 +03:00
FallibleTArray < PRUint8 > * aHeader ,
FontDataOverlay * aOverlay )
2008-10-01 07:01:53 +04:00
{
2008-10-29 21:09:50 +03:00
NS_ASSERTION ( aFontData & & aFontDataLength ! = 0 , " null font data " ) ;
2008-10-01 07:01:53 +04:00
NS_ASSERTION ( aHeader , " null header " ) ;
NS_ASSERTION ( aHeader - > Length ( ) = = 0 , " non-empty header passed in " ) ;
2009-07-23 12:08:23 +04:00
NS_ASSERTION ( aOverlay , " null font overlay struct passed in " ) ;
2008-10-29 21:09:50 +03:00
2009-07-23 12:08:23 +04:00
aOverlay - > overlaySrc = 0 ;
2008-10-01 07:01:53 +04:00
if ( ! aHeader - > AppendElements ( sizeof ( EOTFixedHeader ) ) )
return NS_ERROR_OUT_OF_MEMORY ;
2008-12-22 08:01:14 +03:00
EOTFixedHeader * eotHeader = reinterpret_cast < EOTFixedHeader * > ( aHeader - > Elements ( ) ) ;
2008-10-01 07:01:53 +04:00
memset ( eotHeader , 0 , sizeof ( EOTFixedHeader ) ) ;
2008-10-29 21:09:50 +03:00
PRUint32 fontDataSize = aFontDataLength ;
2008-10-01 07:01:53 +04:00
// set up header fields
eotHeader - > fontDataSize = fontDataSize ;
eotHeader - > version = EOTFixedHeader : : EOT_VERSION ;
eotHeader - > flags = 0 ; // don't specify any special processing
eotHeader - > charset = EOTFixedHeader : : EOT_DEFAULT_CHARSET ;
eotHeader - > fsType = EOTFixedHeader : : EOT_EMBED_PRINT_PREVIEW ;
eotHeader - > magicNumber = EOTFixedHeader : : EOT_MAGIC_NUMBER ;
// read in the sfnt header
2008-10-29 21:09:50 +03:00
if ( sizeof ( SFNTHeader ) > aFontDataLength )
return NS_ERROR_FAILURE ;
const SFNTHeader * sfntHeader = reinterpret_cast < const SFNTHeader * > ( aFontData ) ;
if ( ! IsValidSFNTVersion ( sfntHeader - > sfntVersion ) )
2008-10-01 07:01:53 +04:00
return NS_ERROR_FAILURE ;
// iterate through the table headers to find the head, name and OS/2 tables
PRBool foundHead = PR_FALSE , foundOS2 = PR_FALSE , foundName = PR_FALSE , foundGlyphs = PR_FALSE ;
PRUint32 headOffset , headLen , nameOffset , nameLen , os2Offset , os2Len ;
PRUint32 i , numTables ;
2008-10-29 21:09:50 +03:00
numTables = sfntHeader - > numTables ;
if ( sizeof ( SFNTHeader ) + sizeof ( TableDirEntry ) * numTables > aFontDataLength )
return NS_ERROR_FAILURE ;
PRUint64 dataLength ( aFontDataLength ) ;
// table directory entries begin immediately following SFNT header
const TableDirEntry * dirEntry = reinterpret_cast < const TableDirEntry * > ( aFontData + sizeof ( SFNTHeader ) ) ;
for ( i = 0 ; i < numTables ; i + + , dirEntry + + ) {
// sanity check on offset, length values
if ( PRUint64 ( dirEntry - > offset ) + PRUint64 ( dirEntry - > length ) > dataLength )
2008-10-01 07:01:53 +04:00
return NS_ERROR_FAILURE ;
2008-10-29 21:09:50 +03:00
switch ( dirEntry - > tag ) {
2008-10-01 07:01:53 +04:00
2009-04-02 12:06:33 +04:00
case TRUETYPE_TAG ( ' h ' , ' e ' , ' a ' , ' d ' ) :
2008-10-01 07:01:53 +04:00
foundHead = PR_TRUE ;
2008-10-29 21:09:50 +03:00
headOffset = dirEntry - > offset ;
headLen = dirEntry - > length ;
2008-10-01 07:01:53 +04:00
if ( headLen < sizeof ( HeadTable ) )
return NS_ERROR_FAILURE ;
break ;
2009-04-02 12:06:33 +04:00
case TRUETYPE_TAG ( ' n ' , ' a ' , ' m ' , ' e ' ) :
2008-10-01 07:01:53 +04:00
foundName = PR_TRUE ;
2008-10-29 21:09:50 +03:00
nameOffset = dirEntry - > offset ;
nameLen = dirEntry - > length ;
2008-10-01 07:01:53 +04:00
break ;
2009-04-02 12:06:33 +04:00
case TRUETYPE_TAG ( ' O ' , ' S ' , ' / ' , ' 2 ' ) :
2008-10-01 07:01:53 +04:00
foundOS2 = PR_TRUE ;
2008-10-29 21:09:50 +03:00
os2Offset = dirEntry - > offset ;
os2Len = dirEntry - > length ;
2008-10-01 07:01:53 +04:00
break ;
2009-04-02 12:06:33 +04:00
case TRUETYPE_TAG ( ' g ' , ' l ' , ' y ' , ' f ' ) : // TrueType-style quadratic glyph table
2008-10-01 07:01:53 +04:00
foundGlyphs = PR_TRUE ;
break ;
2009-04-02 12:06:33 +04:00
case TRUETYPE_TAG ( ' C ' , ' F ' , ' F ' , ' ' ) : // PS-style cubic glyph table
2008-10-01 07:01:53 +04:00
foundGlyphs = PR_TRUE ;
break ;
default :
break ;
}
if ( foundHead & & foundName & & foundOS2 & & foundGlyphs )
break ;
}
// require these three tables on Windows
if ( ! foundHead | | ! foundName | | ! foundOS2 )
return NS_ERROR_FAILURE ;
2008-10-29 21:09:50 +03:00
// at this point, all table offset/length values are within bounds
2008-10-01 07:01:53 +04:00
// read in the data from those tables
// -- head table data
2008-10-29 21:09:50 +03:00
const HeadTable * headData = reinterpret_cast < const HeadTable * > ( aFontData + headOffset ) ;
2010-08-17 18:49:40 +04:00
if ( headData - > tableVersionNumber ! = HeadTable : : HEAD_VERSION | |
headData - > magicNumber ! = HeadTable : : HEAD_MAGIC_NUMBER ) {
2008-10-01 07:01:53 +04:00
return NS_ERROR_FAILURE ;
2010-08-17 18:49:40 +04:00
}
2008-10-01 07:01:53 +04:00
2008-10-29 21:09:50 +03:00
eotHeader - > checkSumAdjustment = headData - > checkSumAdjustment ;
2008-10-01 07:01:53 +04:00
// -- name table data
// -- first, read name table header
2008-10-29 21:09:50 +03:00
const NameHeader * nameHeader = reinterpret_cast < const NameHeader * > ( aFontData + nameOffset ) ;
2009-07-23 12:08:23 +04:00
PRUint32 nameStringsBase = PRUint32 ( nameHeader - > stringOffset ) ;
2008-10-01 07:01:53 +04:00
2008-10-29 21:09:50 +03:00
PRUint32 nameCount = nameHeader - > count ;
2008-10-01 07:01:53 +04:00
2008-10-29 21:09:50 +03:00
// -- sanity check the number of name records
if ( PRUint64 ( nameCount ) * sizeof ( NameRecord ) + PRUint64 ( nameOffset ) > dataLength )
return NS_ERROR_FAILURE ;
2008-10-01 07:01:53 +04:00
// -- iterate through name records, look for specific name ids with
// matching platform/encoding/etc. and store offset/lengths
NameRecordData names [ EOTFixedHeader : : EOT_NUM_NAMES ] = { 0 } ;
2008-10-29 21:09:50 +03:00
const NameRecord * nameRecord = reinterpret_cast < const NameRecord * > ( aFontData + nameOffset + sizeof ( NameHeader ) ) ;
2009-02-25 10:12:53 +03:00
PRUint32 needNames = ( 1 < < EOTFixedHeader : : EOT_FAMILY_NAME_INDEX ) |
( 1 < < EOTFixedHeader : : EOT_STYLE_NAME_INDEX ) |
( 1 < < EOTFixedHeader : : EOT_FULL_NAME_INDEX ) |
( 1 < < EOTFixedHeader : : EOT_VERSION_NAME_INDEX ) ;
2008-10-01 07:01:53 +04:00
2008-10-29 21:09:50 +03:00
for ( i = 0 ; i < nameCount ; i + + , nameRecord + + ) {
2008-10-01 07:01:53 +04:00
// looking for Microsoft English US name strings, skip others
2009-08-16 17:52:12 +04:00
if ( PRUint32 ( nameRecord - > platformID ) ! = PLATFORM_ID_MICROSOFT | |
PRUint32 ( nameRecord - > encodingID ) ! = ENCODING_ID_MICROSOFT_UNICODEBMP | |
PRUint32 ( nameRecord - > languageID ) ! = LANG_ID_MICROSOFT_EN_US )
2008-10-01 07:01:53 +04:00
continue ;
2008-10-29 21:09:50 +03:00
switch ( ( PRUint32 ) nameRecord - > nameID ) {
2008-10-01 07:01:53 +04:00
2009-08-16 17:52:12 +04:00
case NAME_ID_FAMILY :
2008-10-29 21:09:50 +03:00
names [ EOTFixedHeader : : EOT_FAMILY_NAME_INDEX ] . offset = nameRecord - > offset ;
names [ EOTFixedHeader : : EOT_FAMILY_NAME_INDEX ] . length = nameRecord - > length ;
2009-02-25 10:12:53 +03:00
needNames & = ~ ( 1 < < EOTFixedHeader : : EOT_FAMILY_NAME_INDEX ) ;
2008-10-01 07:01:53 +04:00
break ;
2009-08-16 17:52:12 +04:00
case NAME_ID_STYLE :
2008-10-29 21:09:50 +03:00
names [ EOTFixedHeader : : EOT_STYLE_NAME_INDEX ] . offset = nameRecord - > offset ;
names [ EOTFixedHeader : : EOT_STYLE_NAME_INDEX ] . length = nameRecord - > length ;
2009-02-25 10:12:53 +03:00
needNames & = ~ ( 1 < < EOTFixedHeader : : EOT_STYLE_NAME_INDEX ) ;
2008-10-01 07:01:53 +04:00
break ;
2009-08-16 17:52:12 +04:00
case NAME_ID_FULL :
2008-10-29 21:09:50 +03:00
names [ EOTFixedHeader : : EOT_FULL_NAME_INDEX ] . offset = nameRecord - > offset ;
names [ EOTFixedHeader : : EOT_FULL_NAME_INDEX ] . length = nameRecord - > length ;
2009-02-25 10:12:53 +03:00
needNames & = ~ ( 1 < < EOTFixedHeader : : EOT_FULL_NAME_INDEX ) ;
2008-10-01 07:01:53 +04:00
break ;
2009-08-16 17:52:12 +04:00
case NAME_ID_VERSION :
2008-10-29 21:09:50 +03:00
names [ EOTFixedHeader : : EOT_VERSION_NAME_INDEX ] . offset = nameRecord - > offset ;
names [ EOTFixedHeader : : EOT_VERSION_NAME_INDEX ] . length = nameRecord - > length ;
2009-02-25 10:12:53 +03:00
needNames & = ~ ( 1 < < EOTFixedHeader : : EOT_VERSION_NAME_INDEX ) ;
2008-10-01 07:01:53 +04:00
break ;
default :
break ;
}
2009-02-25 10:12:53 +03:00
if ( needNames = = 0 )
2008-10-01 07:01:53 +04:00
break ;
}
2010-04-16 12:08:36 +04:00
// the Version name is allowed to be null
if ( ( needNames & ~ ( 1 < < EOTFixedHeader : : EOT_VERSION_NAME_INDEX ) ) ! = 0 ) {
2008-10-01 07:01:53 +04:00
return NS_ERROR_FAILURE ;
2009-07-23 12:08:23 +04:00
}
2008-10-01 07:01:53 +04:00
// -- expand buffer if needed to include variable-length portion
PRUint32 eotVariableLength = 0 ;
eotVariableLength = ( names [ EOTFixedHeader : : EOT_FAMILY_NAME_INDEX ] . length & ( ~ 1 ) ) +
( names [ EOTFixedHeader : : EOT_STYLE_NAME_INDEX ] . length & ( ~ 1 ) ) +
( names [ EOTFixedHeader : : EOT_FULL_NAME_INDEX ] . length & ( ~ 1 ) ) +
( names [ EOTFixedHeader : : EOT_VERSION_NAME_INDEX ] . length & ( ~ 1 ) ) +
EOTFixedHeader : : EOT_NUM_NAMES * ( 2 /* size */
+ 2 /* padding */ ) +
2 /* null root string size */ ;
if ( ! aHeader - > AppendElements ( eotVariableLength ) )
return NS_ERROR_OUT_OF_MEMORY ;
// append the string data to the end of the EOT header
PRUint8 * eotEnd = aHeader - > Elements ( ) + sizeof ( EOTFixedHeader ) ;
2008-10-29 21:09:50 +03:00
PRUint32 strOffset , strLen ;
2008-10-01 07:01:53 +04:00
for ( i = 0 ; i < EOTFixedHeader : : EOT_NUM_NAMES ; i + + ) {
PRUint32 namelen = names [ i ] . length ;
PRUint32 nameoff = names [ i ] . offset ; // offset from base of string storage
2008-10-29 21:09:50 +03:00
// sanity check the name string location
2009-12-20 20:52:57 +03:00
if ( PRUint64 ( nameOffset ) + PRUint64 ( nameStringsBase ) +
PRUint64 ( nameoff ) + PRUint64 ( namelen ) > dataLength ) {
2008-10-01 07:01:53 +04:00
return NS_ERROR_FAILURE ;
2009-07-23 12:08:23 +04:00
}
2008-10-01 07:01:53 +04:00
2009-12-20 20:52:57 +03:00
strOffset = nameOffset + nameStringsBase + nameoff ;
// output 2-byte str size
2008-10-01 07:01:53 +04:00
strLen = namelen & ( ~ 1 ) ; // UTF-16 string len must be even
* ( ( PRUint16 * ) eotEnd ) = PRUint16 ( strLen ) ;
eotEnd + = 2 ;
2009-12-20 20:52:57 +03:00
// length is number of UTF-16 chars, not bytes
CopySwapUTF16 ( reinterpret_cast < const PRUint16 * > ( aFontData + strOffset ) ,
reinterpret_cast < PRUint16 * > ( eotEnd ) ,
( strLen > > 1 ) ) ;
2008-10-01 07:01:53 +04:00
eotEnd + = strLen ;
// add 2-byte zero padding to the end of each string
* eotEnd + + = 0 ;
* eotEnd + + = 0 ;
// Note: Microsoft's WEFT tool produces name strings which
// include an extra null at the end of each string, in addition
// to the 2-byte zero padding that separates the string fields.
// Don't think this is important to imitate...
}
// append null root string size
* eotEnd + + = 0 ;
* eotEnd + + = 0 ;
NS_ASSERTION ( eotEnd = = aHeader - > Elements ( ) + aHeader - > Length ( ) ,
" header length calculation incorrect " ) ;
2009-07-23 12:08:23 +04:00
// bug 496573 -- fonts with a fullname that does not begin with the
// family name cause the EOT font loading API to hiccup
PRUint32 famOff = names [ EOTFixedHeader : : EOT_FAMILY_NAME_INDEX ] . offset ;
PRUint32 famLen = names [ EOTFixedHeader : : EOT_FAMILY_NAME_INDEX ] . length ;
PRUint32 fullOff = names [ EOTFixedHeader : : EOT_FULL_NAME_INDEX ] . offset ;
PRUint32 fullLen = names [ EOTFixedHeader : : EOT_FULL_NAME_INDEX ] . length ;
const PRUint8 * nameStrings = aFontData + nameOffset + nameStringsBase ;
// assure that the start of the fullname matches the family name
if ( famLen < = fullLen
& & memcmp ( nameStrings + famOff , nameStrings + fullOff , famLen ) ) {
aOverlay - > overlaySrc = nameOffset + nameStringsBase + famOff ;
aOverlay - > overlaySrcLen = famLen ;
aOverlay - > overlayDest = nameOffset + nameStringsBase + fullOff ;
}
2008-10-01 07:01:53 +04:00
// -- OS/2 table data
2008-10-29 21:09:50 +03:00
const OS2Table * os2Data = reinterpret_cast < const OS2Table * > ( aFontData + os2Offset ) ;
2008-10-01 07:01:53 +04:00
2008-10-29 21:09:50 +03:00
memcpy ( eotHeader - > panose , os2Data - > panose , sizeof ( eotHeader - > panose ) ) ;
2008-10-01 07:01:53 +04:00
2008-10-29 21:09:50 +03:00
eotHeader - > italic = ( PRUint16 ) os2Data - > fsSelection & 0x01 ;
eotHeader - > weight = os2Data - > usWeightClass ;
eotHeader - > unicodeRange1 = os2Data - > unicodeRange1 ;
eotHeader - > unicodeRange2 = os2Data - > unicodeRange2 ;
eotHeader - > unicodeRange3 = os2Data - > unicodeRange3 ;
eotHeader - > unicodeRange4 = os2Data - > unicodeRange4 ;
eotHeader - > codePageRange1 = os2Data - > codePageRange1 ;
eotHeader - > codePageRange2 = os2Data - > codePageRange2 ;
2008-10-01 07:01:53 +04:00
eotHeader - > eotSize = aHeader - > Length ( ) + fontDataSize ;
// DumpEOTHeader(aHeader->Elements(), aHeader->Length());
return NS_OK ;
}
2009-08-30 17:55:24 +04:00
/* static */
PRBool
2011-03-24 23:11:38 +03:00
gfxFontUtils : : IsCffFont ( const PRUint8 * aFontData , PRBool & hasVertical )
2009-08-30 17:55:24 +04:00
{
// this is only called after aFontData has passed basic validation,
// so we know there is enough data present to allow us to read the version!
const SFNTHeader * sfntHeader = reinterpret_cast < const SFNTHeader * > ( aFontData ) ;
2011-03-24 23:11:38 +03:00
PRUint32 i ;
PRUint32 numTables = sfntHeader - > numTables ;
const TableDirEntry * dirEntry =
reinterpret_cast < const TableDirEntry * > ( aFontData + sizeof ( SFNTHeader ) ) ;
hasVertical = PR_FALSE ;
for ( i = 0 ; i < numTables ; i + + , dirEntry + + ) {
if ( dirEntry - > tag = = TRUETYPE_TAG ( ' v ' , ' h ' , ' e ' , ' a ' ) ) {
hasVertical = PR_TRUE ;
break ;
}
}
2009-08-30 17:55:24 +04:00
return ( sfntHeader - > sfntVersion = = TRUETYPE_TAG ( ' O ' , ' T ' , ' T ' , ' O ' ) ) ;
}
2009-07-29 13:40:33 +04:00
# endif