LCOV - code coverage report
Current view: directory - gfx/thebes - gfxFontUtils.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 662 0 0.0 %
Date: 2012-06-02 Functions: 27 0 0.0 %

       1                 : /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2                 : /* ***** BEGIN LICENSE BLOCK *****
       3                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       4                 :  *
       5                 :  * The contents of this file are subject to the Mozilla Public License Version
       6                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       7                 :  * the License. You may obtain a copy of the License at
       8                 :  * http://www.mozilla.org/MPL/
       9                 :  *
      10                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      11                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      12                 :  * for the specific language governing rights and limitations under the
      13                 :  * License.
      14                 :  *
      15                 :  * The Original Code is thebes gfx code.
      16                 :  *
      17                 :  * The Initial Developer of the Original Code is Mozilla Foundation.
      18                 :  * Portions created by the Initial Developer are Copyright (C) 2007-2009
      19                 :  * the Initial Developer. All Rights Reserved.
      20                 :  *
      21                 :  * Contributor(s):
      22                 :  *   Stuart Parmenter <stuart@mozilla.com>
      23                 :  *   John Daggett <jdaggett@mozilla.com>
      24                 :  *   Jonathan Kew <jfkthame@gmail.com>
      25                 :  *
      26                 :  * Alternatively, the contents of this file may be used under the terms of
      27                 :  * either the GNU General Public License Version 2 or later (the "GPL"), or
      28                 :  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      29                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      30                 :  * of those above. If you wish to allow use of your version of this file only
      31                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      32                 :  * use your version of this file under the terms of the MPL, indicate your
      33                 :  * decision by deleting the provisions above and replace them with the notice
      34                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      35                 :  * the provisions above, a recipient may use your version of this file under
      36                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      37                 :  *
      38                 :  * ***** END LICENSE BLOCK ***** */
      39                 : 
      40                 : #ifdef MOZ_LOGGING
      41                 : #define FORCE_PR_LOG /* Allow logging in the release build */
      42                 : #endif
      43                 : #include "prlog.h"
      44                 : 
      45                 : #include "mozilla/Util.h"
      46                 : 
      47                 : #include "gfxFontUtils.h"
      48                 : 
      49                 : #include "nsServiceManagerUtils.h"
      50                 : 
      51                 : #include "mozilla/Preferences.h"
      52                 : 
      53                 : #include "nsIStreamBufferAccess.h"
      54                 : #include "nsIUUIDGenerator.h"
      55                 : #include "nsMemory.h"
      56                 : #include "nsICharsetConverterManager.h"
      57                 : 
      58                 : #include "plbase64.h"
      59                 : #include "prlog.h"
      60                 : 
      61                 : #include "woff.h"
      62                 : 
      63                 : #ifdef XP_MACOSX
      64                 : #include <CoreFoundation/CoreFoundation.h>
      65                 : #endif
      66                 : 
      67                 : #ifdef PR_LOGGING
      68                 : 
      69                 : #define LOG(log, args) PR_LOG(gfxPlatform::GetLog(log), \
      70                 :                                PR_LOG_DEBUG, args)
      71                 : 
      72                 : #endif // PR_LOGGING
      73                 : 
      74                 : #define NO_RANGE_FOUND 126 // bit 126 in the font unicode ranges is required to be 0
      75                 : 
      76                 : #define UNICODE_BMP_LIMIT 0x10000
      77                 : 
      78                 : using namespace mozilla;
      79                 : 
      80                 : /* Unicode subrange table
      81                 :  *   from: http://msdn.microsoft.com/en-us/library/dd374090
      82                 :  *
      83                 :  * Edit the text to extend the initial digit, then use something like:
      84                 :  * perl -pi -e 's/^(\d+)\t([\dA-Fa-f]+)\s+-\s+([\dA-Fa-f]+)\s+\b([a-zA-Z0-9\(\)\- ]+)/    { \1, 0x\2, 0x\3, \"\4\" },/' < unicoderange.txt
      85                 :  * to generate the below list.
      86                 :  */
      87                 : struct UnicodeRangeTableEntry
      88                 : {
      89                 :     PRUint8 bit;
      90                 :     PRUint32 start;
      91                 :     PRUint32 end;
      92                 :     const char *info;
      93                 : };
      94                 : 
      95                 : static struct UnicodeRangeTableEntry gUnicodeRanges[] = {
      96                 :     { 0, 0x0000, 0x007F, "Basic Latin" },
      97                 :     { 1, 0x0080, 0x00FF, "Latin-1 Supplement" },
      98                 :     { 2, 0x0100, 0x017F, "Latin Extended-A" },
      99                 :     { 3, 0x0180, 0x024F, "Latin Extended-B" },
     100                 :     { 4, 0x0250, 0x02AF, "IPA Extensions" },
     101                 :     { 4, 0x1D00, 0x1D7F, "Phonetic Extensions" },
     102                 :     { 4, 0x1D80, 0x1DBF, "Phonetic Extensions Supplement" },
     103                 :     { 5, 0x02B0, 0x02FF, "Spacing Modifier Letters" },
     104                 :     { 5, 0xA700, 0xA71F, "Modifier Tone Letters" },
     105                 :     { 6, 0x0300, 0x036F, "Combining Diacritical Marks" },
     106                 :     { 6, 0x1DC0, 0x1DFF, "Combining Diacritical Marks Supplement" },
     107                 :     { 7, 0x0370, 0x03FF, "Greek and Coptic" },
     108                 :     { 8, 0x2C80, 0x2CFF, "Coptic" },
     109                 :     { 9, 0x0400, 0x04FF, "Cyrillic" },
     110                 :     { 9, 0x0500, 0x052F, "Cyrillic Supplement" },
     111                 :     { 9, 0x2DE0, 0x2DFF, "Cyrillic Extended-A" },
     112                 :     { 9, 0xA640, 0xA69F, "Cyrillic Extended-B" },
     113                 :     { 10, 0x0530, 0x058F, "Armenian" },
     114                 :     { 11, 0x0590, 0x05FF, "Hebrew" },
     115                 :     { 12, 0xA500, 0xA63F, "Vai" },
     116                 :     { 13, 0x0600, 0x06FF, "Arabic" },
     117                 :     { 13, 0x0750, 0x077F, "Arabic Supplement" },
     118                 :     { 14, 0x07C0, 0x07FF, "NKo" },
     119                 :     { 15, 0x0900, 0x097F, "Devanagari" },
     120                 :     { 16, 0x0980, 0x09FF, "Bengali" },
     121                 :     { 17, 0x0A00, 0x0A7F, "Gurmukhi" },
     122                 :     { 18, 0x0A80, 0x0AFF, "Gujarati" },
     123                 :     { 19, 0x0B00, 0x0B7F, "Oriya" },
     124                 :     { 20, 0x0B80, 0x0BFF, "Tamil" },
     125                 :     { 21, 0x0C00, 0x0C7F, "Telugu" },
     126                 :     { 22, 0x0C80, 0x0CFF, "Kannada" },
     127                 :     { 23, 0x0D00, 0x0D7F, "Malayalam" },
     128                 :     { 24, 0x0E00, 0x0E7F, "Thai" },
     129                 :     { 25, 0x0E80, 0x0EFF, "Lao" },
     130                 :     { 26, 0x10A0, 0x10FF, "Georgian" },
     131                 :     { 26, 0x2D00, 0x2D2F, "Georgian Supplement" },
     132                 :     { 27, 0x1B00, 0x1B7F, "Balinese" },
     133                 :     { 28, 0x1100, 0x11FF, "Hangul Jamo" },
     134                 :     { 29, 0x1E00, 0x1EFF, "Latin Extended Additional" },
     135                 :     { 29, 0x2C60, 0x2C7F, "Latin Extended-C" },
     136                 :     { 29, 0xA720, 0xA7FF, "Latin Extended-D" },
     137                 :     { 30, 0x1F00, 0x1FFF, "Greek Extended" },
     138                 :     { 31, 0x2000, 0x206F, "General Punctuation" },
     139                 :     { 31, 0x2E00, 0x2E7F, "Supplemental Punctuation" },
     140                 :     { 32, 0x2070, 0x209F, "Superscripts And Subscripts" },
     141                 :     { 33, 0x20A0, 0x20CF, "Currency Symbols" },
     142                 :     { 34, 0x20D0, 0x20FF, "Combining Diacritical Marks For Symbols" },
     143                 :     { 35, 0x2100, 0x214F, "Letterlike Symbols" },
     144                 :     { 36, 0x2150, 0x218F, "Number Forms" },
     145                 :     { 37, 0x2190, 0x21FF, "Arrows" },
     146                 :     { 37, 0x27F0, 0x27FF, "Supplemental Arrows-A" },
     147                 :     { 37, 0x2900, 0x297F, "Supplemental Arrows-B" },
     148                 :     { 37, 0x2B00, 0x2BFF, "Miscellaneous Symbols and Arrows" },
     149                 :     { 38, 0x2200, 0x22FF, "Mathematical Operators" },
     150                 :     { 38, 0x27C0, 0x27EF, "Miscellaneous Mathematical Symbols-A" },
     151                 :     { 38, 0x2980, 0x29FF, "Miscellaneous Mathematical Symbols-B" },
     152                 :     { 38, 0x2A00, 0x2AFF, "Supplemental Mathematical Operators" },
     153                 :     { 39, 0x2300, 0x23FF, "Miscellaneous Technical" },
     154                 :     { 40, 0x2400, 0x243F, "Control Pictures" },
     155                 :     { 41, 0x2440, 0x245F, "Optical Character Recognition" },
     156                 :     { 42, 0x2460, 0x24FF, "Enclosed Alphanumerics" },
     157                 :     { 43, 0x2500, 0x257F, "Box Drawing" },
     158                 :     { 44, 0x2580, 0x259F, "Block Elements" },
     159                 :     { 45, 0x25A0, 0x25FF, "Geometric Shapes" },
     160                 :     { 46, 0x2600, 0x26FF, "Miscellaneous Symbols" },
     161                 :     { 47, 0x2700, 0x27BF, "Dingbats" },
     162                 :     { 48, 0x3000, 0x303F, "CJK Symbols And Punctuation" },
     163                 :     { 49, 0x3040, 0x309F, "Hiragana" },
     164                 :     { 50, 0x30A0, 0x30FF, "Katakana" },
     165                 :     { 50, 0x31F0, 0x31FF, "Katakana Phonetic Extensions" },
     166                 :     { 51, 0x3100, 0x312F, "Bopomofo" },
     167                 :     { 50, 0x31A0, 0x31BF, "Bopomofo Extended" },
     168                 :     { 52, 0x3130, 0x318F, "Hangul Compatibility Jamo" },
     169                 :     { 53, 0xA840, 0xA87F, "Phags-pa" },
     170                 :     { 54, 0x3200, 0x32FF, "Enclosed CJK Letters And Months" },
     171                 :     { 55, 0x3300, 0x33FF, "CJK Compatibility" },
     172                 :     { 56, 0xAC00, 0xD7AF, "Hangul Syllables" },
     173                 :     { 57, 0xD800, 0xDFFF, "Non-Plane 0" },
     174                 :     { 58, 0x10900, 0x1091F, "Phoenician" },
     175                 :     { 59, 0x2E80, 0x2EFF, "CJK Radicals Supplement" },
     176                 :     { 59, 0x2F00, 0x2FDF, "Kangxi Radicals" },
     177                 :     { 59, 0x2FF0, 0x2FFF, "Ideographic Description Characters" },
     178                 :     { 59, 0x3190, 0x319F, "Kanbun" },
     179                 :     { 59, 0x3400, 0x4DBF, "CJK Unified Ideographs Extension A" },
     180                 :     { 59, 0x4E00, 0x9FFF, "CJK Unified Ideographs" },
     181                 :     { 59, 0x20000, 0x2A6DF, "CJK Unified Ideographs Extension B" },
     182                 :     { 60, 0xE000, 0xF8FF, "Private Use Area" },
     183                 :     { 61, 0x31C0, 0x31EF, "CJK Strokes" },
     184                 :     { 61, 0xF900, 0xFAFF, "CJK Compatibility Ideographs" },
     185                 :     { 61, 0x2F800, 0x2FA1F, "CJK Compatibility Ideographs Supplement" },
     186                 :     { 62, 0xFB00, 0xFB4F, "Alphabetic Presentation Forms" },
     187                 :     { 63, 0xFB50, 0xFDFF, "Arabic Presentation Forms-A" },
     188                 :     { 64, 0xFE20, 0xFE2F, "Combining Half Marks" },
     189                 :     { 65, 0xFE10, 0xFE1F, "Vertical Forms" },
     190                 :     { 65, 0xFE30, 0xFE4F, "CJK Compatibility Forms" },
     191                 :     { 66, 0xFE50, 0xFE6F, "Small Form Variants" },
     192                 :     { 67, 0xFE70, 0xFEFF, "Arabic Presentation Forms-B" },
     193                 :     { 68, 0xFF00, 0xFFEF, "Halfwidth And Fullwidth Forms" },
     194                 :     { 69, 0xFFF0, 0xFFFF, "Specials" },
     195                 :     { 70, 0x0F00, 0x0FFF, "Tibetan" },
     196                 :     { 71, 0x0700, 0x074F, "Syriac" },
     197                 :     { 72, 0x0780, 0x07BF, "Thaana" },
     198                 :     { 73, 0x0D80, 0x0DFF, "Sinhala" },
     199                 :     { 74, 0x1000, 0x109F, "Myanmar" },
     200                 :     { 75, 0x1200, 0x137F, "Ethiopic" },
     201                 :     { 75, 0x1380, 0x139F, "Ethiopic Supplement" },
     202                 :     { 75, 0x2D80, 0x2DDF, "Ethiopic Extended" },
     203                 :     { 76, 0x13A0, 0x13FF, "Cherokee" },
     204                 :     { 77, 0x1400, 0x167F, "Unified Canadian Aboriginal Syllabics" },
     205                 :     { 78, 0x1680, 0x169F, "Ogham" },
     206                 :     { 79, 0x16A0, 0x16FF, "Runic" },
     207                 :     { 80, 0x1780, 0x17FF, "Khmer" },
     208                 :     { 80, 0x19E0, 0x19FF, "Khmer Symbols" },
     209                 :     { 81, 0x1800, 0x18AF, "Mongolian" },
     210                 :     { 82, 0x2800, 0x28FF, "Braille Patterns" },
     211                 :     { 83, 0xA000, 0xA48F, "Yi Syllables" },
     212                 :     { 83, 0xA490, 0xA4CF, "Yi Radicals" },
     213                 :     { 84, 0x1700, 0x171F, "Tagalog" },
     214                 :     { 84, 0x1720, 0x173F, "Hanunoo" },
     215                 :     { 84, 0x1740, 0x175F, "Buhid" },
     216                 :     { 84, 0x1760, 0x177F, "Tagbanwa" },
     217                 :     { 85, 0x10300, 0x1032F, "Old Italic" },
     218                 :     { 86, 0x10330, 0x1034F, "Gothic" },
     219                 :     { 87, 0x10400, 0x1044F, "Deseret" },
     220                 :     { 88, 0x1D000, 0x1D0FF, "Byzantine Musical Symbols" },
     221                 :     { 88, 0x1D100, 0x1D1FF, "Musical Symbols" },
     222                 :     { 88, 0x1D200, 0x1D24F, "Ancient Greek Musical Notation" },
     223                 :     { 89, 0x1D400, 0x1D7FF, "Mathematical Alphanumeric Symbols" },
     224                 :     { 90, 0xFF000, 0xFFFFD, "Private Use (plane 15)" },
     225                 :     { 90, 0x100000, 0x10FFFD, "Private Use (plane 16)" },
     226                 :     { 91, 0xFE00, 0xFE0F, "Variation Selectors" },
     227                 :     { 91, 0xE0100, 0xE01EF, "Variation Selectors Supplement" },
     228                 :     { 92, 0xE0000, 0xE007F, "Tags" },
     229                 :     { 93, 0x1900, 0x194F, "Limbu" },
     230                 :     { 94, 0x1950, 0x197F, "Tai Le" },
     231                 :     { 95, 0x1980, 0x19DF, "New Tai Lue" },
     232                 :     { 96, 0x1A00, 0x1A1F, "Buginese" },
     233                 :     { 97, 0x2C00, 0x2C5F, "Glagolitic" },
     234                 :     { 98, 0x2D30, 0x2D7F, "Tifinagh" },
     235                 :     { 99, 0x4DC0, 0x4DFF, "Yijing Hexagram Symbols" },
     236                 :     { 100, 0xA800, 0xA82F, "Syloti Nagri" },
     237                 :     { 101, 0x10000, 0x1007F, "Linear B Syllabary" },
     238                 :     { 101, 0x10080, 0x100FF, "Linear B Ideograms" },
     239                 :     { 101, 0x10100, 0x1013F, "Aegean Numbers" },
     240                 :     { 102, 0x10140, 0x1018F, "Ancient Greek Numbers" },
     241                 :     { 103, 0x10380, 0x1039F, "Ugaritic" },
     242                 :     { 104, 0x103A0, 0x103DF, "Old Persian" },
     243                 :     { 105, 0x10450, 0x1047F, "Shavian" },
     244                 :     { 106, 0x10480, 0x104AF, "Osmanya" },
     245                 :     { 107, 0x10800, 0x1083F, "Cypriot Syllabary" },
     246                 :     { 108, 0x10A00, 0x10A5F, "Kharoshthi" },
     247                 :     { 109, 0x1D300, 0x1D35F, "Tai Xuan Jing Symbols" },
     248                 :     { 110, 0x12000, 0x123FF, "Cuneiform" },
     249                 :     { 110, 0x12400, 0x1247F, "Cuneiform Numbers and Punctuation" },
     250                 :     { 111, 0x1D360, 0x1D37F, "Counting Rod Numerals" },
     251                 :     { 112, 0x1B80, 0x1BBF, "Sundanese" },
     252                 :     { 113, 0x1C00, 0x1C4F, "Lepcha" },
     253                 :     { 114, 0x1C50, 0x1C7F, "Ol Chiki" },
     254                 :     { 115, 0xA880, 0xA8DF, "Saurashtra" },
     255                 :     { 116, 0xA900, 0xA92F, "Kayah Li" },
     256                 :     { 117, 0xA930, 0xA95F, "Rejang" },
     257                 :     { 118, 0xAA00, 0xAA5F, "Cham" },
     258                 :     { 119, 0x10190, 0x101CF, "Ancient Symbols" },
     259                 :     { 120, 0x101D0, 0x101FF, "Phaistos Disc" },
     260                 :     { 121, 0x10280, 0x1029F, "Lycian" },
     261                 :     { 121, 0x102A0, 0x102DF, "Carian" },
     262                 :     { 121, 0x10920, 0x1093F, "Lydian" },
     263                 :     { 122, 0x1F000, 0x1F02F, "Mahjong Tiles" },
     264                 :     { 122, 0x1F030, 0x1F09F, "Domino Tiles" }
     265                 : };
     266                 : 
     267                 : #pragma pack(1)
     268                 : 
     269                 : typedef struct {
     270                 :     AutoSwap_PRUint16 format;
     271                 :     AutoSwap_PRUint16 reserved;
     272                 :     AutoSwap_PRUint32 length;
     273                 :     AutoSwap_PRUint32 language;
     274                 :     AutoSwap_PRUint32 numGroups;
     275                 : } Format12CmapHeader;
     276                 : 
     277                 : typedef struct {
     278                 :     AutoSwap_PRUint32 startCharCode;
     279                 :     AutoSwap_PRUint32 endCharCode;
     280                 :     AutoSwap_PRUint32 startGlyphId;
     281                 : } Format12Group;
     282                 : 
     283                 : #pragma pack()
     284                 : 
     285                 : #if PR_LOGGING
     286                 : void
     287               0 : gfxSparseBitSet::Dump(const char* aPrefix, eGfxLog aWhichLog) const
     288                 : {
     289               0 :     NS_ASSERTION(mBlocks.DebugGetHeader(), "mHdr is null, this is bad");
     290               0 :     PRUint32 b, numBlocks = mBlocks.Length();
     291                 : 
     292               0 :     for (b = 0; b < numBlocks; b++) {
     293               0 :         Block *block = mBlocks[b];
     294               0 :         if (!block) continue;
     295                 :         char outStr[256];
     296               0 :         int index = 0;
     297               0 :         index += sprintf(&outStr[index], "%s u+%6.6x [", aPrefix, (b << BLOCK_INDEX_SHIFT));
     298               0 :         for (int i = 0; i < 32; i += 4) {
     299               0 :             for (int j = i; j < i + 4; j++) {
     300               0 :                 PRUint8 bits = block->mBits[j];
     301               0 :                 PRUint8 flip1 = ((bits & 0xaa) >> 1) | ((bits & 0x55) << 1);
     302               0 :                 PRUint8 flip2 = ((flip1 & 0xcc) >> 2) | ((flip1 & 0x33) << 2);
     303               0 :                 PRUint8 flipped = ((flip2 & 0xf0) >> 4) | ((flip2 & 0x0f) << 4);
     304                 : 
     305               0 :                 index += sprintf(&outStr[index], "%2.2x", flipped);
     306                 :             }
     307               0 :             if (i + 4 != 32) index += sprintf(&outStr[index], " ");
     308                 :         }
     309               0 :         index += sprintf(&outStr[index], "]");
     310               0 :         LOG(aWhichLog, ("%s", outStr));
     311                 :     }
     312               0 : }
     313                 : #endif
     314                 : 
     315                 : 
     316                 : nsresult
     317               0 : gfxFontUtils::ReadCMAPTableFormat12(const PRUint8 *aBuf, PRUint32 aLength,
     318                 :                                     gfxSparseBitSet& aCharacterMap) 
     319                 : {
     320                 :     // Ensure table is large enough that we can safely read the header
     321               0 :     NS_ENSURE_TRUE(aLength >= sizeof(Format12CmapHeader),
     322                 :                     NS_ERROR_GFX_CMAP_MALFORMED);
     323                 : 
     324                 :     // Sanity-check header fields
     325                 :     const Format12CmapHeader *cmap12 =
     326               0 :         reinterpret_cast<const Format12CmapHeader*>(aBuf);
     327               0 :     NS_ENSURE_TRUE(PRUint16(cmap12->format) == 12, 
     328                 :                    NS_ERROR_GFX_CMAP_MALFORMED);
     329               0 :     NS_ENSURE_TRUE(PRUint16(cmap12->reserved) == 0, 
     330                 :                    NS_ERROR_GFX_CMAP_MALFORMED);
     331                 : 
     332               0 :     PRUint32 tablelen = cmap12->length;
     333               0 :     NS_ENSURE_TRUE(tablelen >= sizeof(Format12CmapHeader) &&
     334                 :                    tablelen <= aLength, NS_ERROR_GFX_CMAP_MALFORMED);
     335                 : 
     336               0 :     NS_ENSURE_TRUE(cmap12->language == 0, NS_ERROR_GFX_CMAP_MALFORMED);
     337                 : 
     338                 :     // Check that the table is large enough for the group array
     339               0 :     const PRUint32 numGroups = cmap12->numGroups;
     340               0 :     NS_ENSURE_TRUE((tablelen - sizeof(Format12CmapHeader)) /
     341                 :                        sizeof(Format12Group) >= numGroups,
     342                 :                    NS_ERROR_GFX_CMAP_MALFORMED);
     343                 : 
     344                 :     // The array of groups immediately follows the subtable header.
     345                 :     const Format12Group *group =
     346               0 :         reinterpret_cast<const Format12Group*>(aBuf + sizeof(Format12CmapHeader));
     347                 : 
     348                 :     // Check that groups are in correct order and do not overlap,
     349                 :     // and record character coverage in aCharacterMap.
     350               0 :     PRUint32 prevEndCharCode = 0;
     351               0 :     for (PRUint32 i = 0; i < numGroups; i++, group++) {
     352               0 :         const PRUint32 startCharCode = group->startCharCode;
     353               0 :         const PRUint32 endCharCode = group->endCharCode;
     354               0 :         NS_ENSURE_TRUE((prevEndCharCode < startCharCode || i == 0) &&
     355                 :                        startCharCode <= endCharCode &&
     356                 :                        endCharCode <= CMAP_MAX_CODEPOINT, 
     357                 :                        NS_ERROR_GFX_CMAP_MALFORMED);
     358               0 :         aCharacterMap.SetRange(startCharCode, endCharCode);
     359               0 :         prevEndCharCode = endCharCode;
     360                 :     }
     361                 : 
     362               0 :     aCharacterMap.Compact();
     363                 : 
     364               0 :     return NS_OK;
     365                 : }
     366                 : 
     367                 : nsresult 
     368               0 : gfxFontUtils::ReadCMAPTableFormat4(const PRUint8 *aBuf, PRUint32 aLength,
     369                 :                                    gfxSparseBitSet& aCharacterMap)
     370                 : {
     371                 :     enum {
     372                 :         OffsetFormat = 0,
     373                 :         OffsetLength = 2,
     374                 :         OffsetLanguage = 4,
     375                 :         OffsetSegCountX2 = 6
     376                 :     };
     377                 : 
     378               0 :     NS_ENSURE_TRUE(ReadShortAt(aBuf, OffsetFormat) == 4, 
     379                 :                    NS_ERROR_GFX_CMAP_MALFORMED);
     380               0 :     PRUint16 tablelen = ReadShortAt(aBuf, OffsetLength);
     381               0 :     NS_ENSURE_TRUE(tablelen <= aLength, NS_ERROR_GFX_CMAP_MALFORMED);
     382               0 :     NS_ENSURE_TRUE(tablelen > 16, NS_ERROR_GFX_CMAP_MALFORMED);
     383                 :     
     384                 :     // This field should normally (except for Mac platform subtables) be zero according to
     385                 :     // the OT spec, but some buggy fonts have lang = 1 (which would be English for MacOS).
     386                 :     // E.g. Arial Narrow Bold, v. 1.1 (Tiger), Arial Unicode MS (see bug 530614).
     387                 :     // So accept either zero or one here; the error should be harmless.
     388               0 :     NS_ENSURE_TRUE((ReadShortAt(aBuf, OffsetLanguage) & 0xfffe) == 0, 
     389                 :                    NS_ERROR_GFX_CMAP_MALFORMED);
     390                 : 
     391               0 :     PRUint16 segCountX2 = ReadShortAt(aBuf, OffsetSegCountX2);
     392               0 :     NS_ENSURE_TRUE(tablelen >= 16 + (segCountX2 * 4), 
     393                 :                    NS_ERROR_GFX_CMAP_MALFORMED);
     394                 : 
     395               0 :     const PRUint16 segCount = segCountX2 / 2;
     396                 : 
     397               0 :     const PRUint16 *endCounts = reinterpret_cast<const PRUint16*>(aBuf + 14);
     398               0 :     const PRUint16 *startCounts = endCounts + 1 /* skip one uint16 for reservedPad */ + segCount;
     399               0 :     const PRUint16 *idDeltas = startCounts + segCount;
     400               0 :     const PRUint16 *idRangeOffsets = idDeltas + segCount;
     401               0 :     PRUint16 prevEndCount = 0;
     402               0 :     for (PRUint16 i = 0; i < segCount; i++) {
     403               0 :         const PRUint16 endCount = ReadShortAt16(endCounts, i);
     404               0 :         const PRUint16 startCount = ReadShortAt16(startCounts, i);
     405               0 :         const PRUint16 idRangeOffset = ReadShortAt16(idRangeOffsets, i);
     406                 : 
     407                 :         // sanity-check range
     408                 :         // This permits ranges to overlap by 1 character, which is strictly
     409                 :         // incorrect but occurs in Baskerville on OS X 10.7 (see bug 689087),
     410                 :         // and appears to be harmless in practice
     411               0 :         NS_ENSURE_TRUE(startCount >= prevEndCount && startCount <= endCount,
     412                 :                        NS_ERROR_GFX_CMAP_MALFORMED);
     413               0 :         prevEndCount = endCount;
     414                 : 
     415               0 :         if (idRangeOffset == 0) {
     416               0 :             aCharacterMap.SetRange(startCount, endCount);
     417                 :         } else {
     418                 :             // const PRUint16 idDelta = ReadShortAt16(idDeltas, i); // Unused: self-documenting.
     419               0 :             for (PRUint32 c = startCount; c <= endCount; ++c) {
     420               0 :                 if (c == 0xFFFF)
     421               0 :                     break;
     422                 : 
     423                 :                 const PRUint16 *gdata = (idRangeOffset/2 
     424                 :                                          + (c - startCount)
     425               0 :                                          + &idRangeOffsets[i]);
     426                 : 
     427               0 :                 NS_ENSURE_TRUE((PRUint8*)gdata > aBuf && 
     428                 :                                (PRUint8*)gdata < aBuf + aLength, 
     429                 :                                NS_ERROR_GFX_CMAP_MALFORMED);
     430                 : 
     431                 :                 // make sure we have a glyph
     432               0 :                 if (*gdata != 0) {
     433                 :                     // The glyph index at this point is:
     434                 :                     // glyph = (ReadShortAt16(idDeltas, i) + *gdata) % 65536;
     435                 : 
     436               0 :                     aCharacterMap.set(c);
     437                 :                 }
     438                 :             }
     439                 :         }
     440                 :     }
     441                 : 
     442               0 :     aCharacterMap.Compact();
     443                 : 
     444               0 :     return NS_OK;
     445                 : }
     446                 : 
     447                 : nsresult
     448               0 : gfxFontUtils::ReadCMAPTableFormat14(const PRUint8 *aBuf, PRUint32 aLength,
     449                 :                                     PRUint8*& aTable)
     450                 : {
     451                 :     enum {
     452                 :         OffsetFormat = 0,
     453                 :         OffsetTableLength = 2,
     454                 :         OffsetNumVarSelectorRecords = 6,
     455                 :         OffsetVarSelectorRecords = 10,
     456                 : 
     457                 :         SizeOfVarSelectorRecord = 11,
     458                 :         VSRecOffsetVarSelector = 0,
     459                 :         VSRecOffsetDefUVSOffset = 3,
     460                 :         VSRecOffsetNonDefUVSOffset = 7,
     461                 : 
     462                 :         SizeOfDefUVSTable = 4,
     463                 :         DefUVSOffsetStartUnicodeValue = 0,
     464                 :         DefUVSOffsetAdditionalCount = 3,
     465                 : 
     466                 :         SizeOfNonDefUVSTable = 5,
     467                 :         NonDefUVSOffsetUnicodeValue = 0,
     468                 :         NonDefUVSOffsetGlyphID = 3
     469                 :     };
     470               0 :     NS_ENSURE_TRUE(aLength >= OffsetVarSelectorRecords,
     471                 :                    NS_ERROR_GFX_CMAP_MALFORMED);
     472                 : 
     473               0 :     NS_ENSURE_TRUE(ReadShortAt(aBuf, OffsetFormat) == 14, 
     474                 :                    NS_ERROR_GFX_CMAP_MALFORMED);
     475                 : 
     476               0 :     PRUint32 tablelen = ReadLongAt(aBuf, OffsetTableLength);
     477               0 :     NS_ENSURE_TRUE(tablelen <= aLength, NS_ERROR_GFX_CMAP_MALFORMED);
     478               0 :     NS_ENSURE_TRUE(tablelen >= OffsetVarSelectorRecords,
     479                 :                    NS_ERROR_GFX_CMAP_MALFORMED);
     480                 : 
     481               0 :     const PRUint32 numVarSelectorRecords = ReadLongAt(aBuf, OffsetNumVarSelectorRecords);
     482               0 :     NS_ENSURE_TRUE((tablelen - OffsetVarSelectorRecords) /
     483                 :                    SizeOfVarSelectorRecord >= numVarSelectorRecords,
     484                 :                    NS_ERROR_GFX_CMAP_MALFORMED);
     485                 : 
     486               0 :     const PRUint8 *records = aBuf + OffsetVarSelectorRecords;
     487               0 :     for (PRUint32 i = 0; i < numVarSelectorRecords; 
     488                 :          i++, records += SizeOfVarSelectorRecord) {
     489               0 :         const PRUint32 varSelector = ReadUint24At(records, VSRecOffsetVarSelector);
     490               0 :         const PRUint32 defUVSOffset = ReadLongAt(records, VSRecOffsetDefUVSOffset);
     491               0 :         const PRUint32 nonDefUVSOffset = ReadLongAt(records, VSRecOffsetNonDefUVSOffset);
     492               0 :         NS_ENSURE_TRUE(varSelector <= CMAP_MAX_CODEPOINT &&
     493                 :                        defUVSOffset <= tablelen - 4 &&
     494                 :                        nonDefUVSOffset <= tablelen - 4, 
     495                 :                        NS_ERROR_GFX_CMAP_MALFORMED);
     496                 : 
     497               0 :         if (defUVSOffset) {
     498               0 :             const PRUint32 numUnicodeValueRanges = ReadLongAt(aBuf, defUVSOffset);
     499               0 :             NS_ENSURE_TRUE((tablelen - defUVSOffset) /
     500                 :                            SizeOfDefUVSTable >= numUnicodeValueRanges,
     501                 :                            NS_ERROR_GFX_CMAP_MALFORMED);
     502               0 :             const PRUint8 *tables = aBuf + defUVSOffset + 4;
     503               0 :             PRUint32 prevEndUnicode = 0;
     504               0 :             for (PRUint32 j = 0; j < numUnicodeValueRanges; j++, tables += SizeOfDefUVSTable) {
     505               0 :                 const PRUint32 startUnicode = ReadUint24At(tables, DefUVSOffsetStartUnicodeValue);
     506               0 :                 const PRUint32 endUnicode = startUnicode + tables[DefUVSOffsetAdditionalCount];
     507               0 :                 NS_ENSURE_TRUE((prevEndUnicode < startUnicode || j == 0) &&
     508                 :                                endUnicode <= CMAP_MAX_CODEPOINT, 
     509                 :                                NS_ERROR_GFX_CMAP_MALFORMED);
     510               0 :                 prevEndUnicode = endUnicode;
     511                 :             }
     512                 :         }
     513                 : 
     514               0 :         if (nonDefUVSOffset) {
     515               0 :             const PRUint32 numUVSMappings = ReadLongAt(aBuf, nonDefUVSOffset);
     516               0 :             NS_ENSURE_TRUE((tablelen - nonDefUVSOffset) /
     517                 :                            SizeOfNonDefUVSTable >= numUVSMappings,
     518                 :                            NS_ERROR_GFX_CMAP_MALFORMED);
     519               0 :             const PRUint8 *tables = aBuf + nonDefUVSOffset + 4;
     520               0 :             PRUint32 prevUnicode = 0;
     521               0 :             for (PRUint32 j = 0; j < numUVSMappings; j++, tables += SizeOfNonDefUVSTable) {
     522               0 :                 const PRUint32 unicodeValue = ReadUint24At(tables, NonDefUVSOffsetUnicodeValue);
     523               0 :                 NS_ENSURE_TRUE((prevUnicode < unicodeValue || j == 0) &&
     524                 :                                unicodeValue <= CMAP_MAX_CODEPOINT, 
     525                 :                                NS_ERROR_GFX_CMAP_MALFORMED);
     526               0 :                 prevUnicode = unicodeValue;
     527                 :             }
     528                 :         }
     529                 :     }
     530                 : 
     531               0 :     aTable = new PRUint8[tablelen];
     532               0 :     memcpy(aTable, aBuf, tablelen);
     533                 : 
     534               0 :     return NS_OK;
     535                 : }
     536                 : 
     537                 : // Windows requires fonts to have a format-4 cmap with a Microsoft ID (3).  On the Mac, fonts either have
     538                 : // a format-4 cmap with Microsoft platform/encoding id or they have one with a platformID == Unicode (0)
     539                 : // For fonts with two format-4 tables, the first one (Unicode platform) is preferred on the Mac.
     540                 : 
     541                 : #if defined(XP_MACOSX)
     542                 :     #define acceptableFormat4(p,e,k) (((p) == PLATFORM_ID_MICROSOFT && (e) == EncodingIDMicrosoft && !(k)) || \
     543                 :                                       ((p) == PLATFORM_ID_UNICODE))
     544                 : 
     545                 :     #define acceptableUCS4Encoding(p, e, k) \
     546                 :         (((p) == PLATFORM_ID_MICROSOFT && (e) == EncodingIDUCS4ForMicrosoftPlatform) && (k) != 12 || \
     547                 :          ((p) == PLATFORM_ID_UNICODE   && \
     548                 :           ((e) == EncodingIDDefaultForUnicodePlatform || (e) >= EncodingIDUCS4ForUnicodePlatform)))
     549                 : #else
     550                 :     #define acceptableFormat4(p,e,k) ((p) == PLATFORM_ID_MICROSOFT && (e) == EncodingIDMicrosoft)
     551                 : 
     552                 :     #define acceptableUCS4Encoding(p, e, k) \
     553                 :         ((p) == PLATFORM_ID_MICROSOFT && (e) == EncodingIDUCS4ForMicrosoftPlatform)
     554                 : #endif
     555                 : 
     556                 : #define acceptablePlatform(p) ((p) == PLATFORM_ID_UNICODE || (p) == PLATFORM_ID_MICROSOFT)
     557                 : #define isSymbol(p,e)         ((p) == PLATFORM_ID_MICROSOFT && (e) == EncodingIDSymbol)
     558                 : #define isUVSEncoding(p, e)   ((p) == PLATFORM_ID_UNICODE && (e) == EncodingIDUVSForUnicodePlatform)
     559                 : 
     560                 : PRUint32
     561               0 : gfxFontUtils::FindPreferredSubtable(const PRUint8 *aBuf, PRUint32 aBufLength,
     562                 :                                     PRUint32 *aTableOffset,
     563                 :                                     PRUint32 *aUVSTableOffset,
     564                 :                                     bool *aSymbolEncoding)
     565                 : {
     566                 :     enum {
     567                 :         OffsetVersion = 0,
     568                 :         OffsetNumTables = 2,
     569                 :         SizeOfHeader = 4,
     570                 : 
     571                 :         TableOffsetPlatformID = 0,
     572                 :         TableOffsetEncodingID = 2,
     573                 :         TableOffsetOffset = 4,
     574                 :         SizeOfTable = 8,
     575                 : 
     576                 :         SubtableOffsetFormat = 0
     577                 :     };
     578                 :     enum {
     579                 :         EncodingIDSymbol = 0,
     580                 :         EncodingIDMicrosoft = 1,
     581                 :         EncodingIDDefaultForUnicodePlatform = 0,
     582                 :         EncodingIDUCS4ForUnicodePlatform = 3,
     583                 :         EncodingIDUVSForUnicodePlatform = 5,
     584                 :         EncodingIDUCS4ForMicrosoftPlatform = 10
     585                 :     };
     586                 : 
     587               0 :     if (aUVSTableOffset) {
     588               0 :         *aUVSTableOffset = nsnull;
     589                 :     }
     590                 : 
     591               0 :     if (!aBuf || aBufLength < SizeOfHeader) {
     592                 :         // cmap table is missing, or too small to contain header fields!
     593               0 :         return 0;
     594                 :     }
     595                 : 
     596                 :     // PRUint16 version = ReadShortAt(aBuf, OffsetVersion); // Unused: self-documenting.
     597               0 :     PRUint16 numTables = ReadShortAt(aBuf, OffsetNumTables);
     598               0 :     if (aBufLength < PRUint32(SizeOfHeader + numTables * SizeOfTable)) {
     599               0 :         return 0;
     600                 :     }
     601                 : 
     602                 :     // save the format we want here
     603               0 :     PRUint32 keepFormat = 0;
     604                 : 
     605               0 :     const PRUint8 *table = aBuf + SizeOfHeader;
     606               0 :     for (PRUint16 i = 0; i < numTables; ++i, table += SizeOfTable) {
     607               0 :         const PRUint16 platformID = ReadShortAt(table, TableOffsetPlatformID);
     608               0 :         if (!acceptablePlatform(platformID))
     609               0 :             continue;
     610                 : 
     611               0 :         const PRUint16 encodingID = ReadShortAt(table, TableOffsetEncodingID);
     612               0 :         const PRUint32 offset = ReadLongAt(table, TableOffsetOffset);
     613               0 :         if (aBufLength - 2 < offset) {
     614                 :             // this subtable is not valid - beyond end of buffer
     615               0 :             return 0;
     616                 :         }
     617                 : 
     618               0 :         const PRUint8 *subtable = aBuf + offset;
     619               0 :         const PRUint16 format = ReadShortAt(subtable, SubtableOffsetFormat);
     620                 : 
     621               0 :         if (isSymbol(platformID, encodingID)) {
     622               0 :             keepFormat = format;
     623               0 :             *aTableOffset = offset;
     624               0 :             *aSymbolEncoding = true;
     625               0 :             break;
     626               0 :         } else if (format == 4 && acceptableFormat4(platformID, encodingID, keepFormat)) {
     627               0 :             keepFormat = format;
     628               0 :             *aTableOffset = offset;
     629               0 :             *aSymbolEncoding = false;
     630               0 :         } else if (format == 12 && acceptableUCS4Encoding(platformID, encodingID, keepFormat)) {
     631               0 :             keepFormat = format;
     632               0 :             *aTableOffset = offset;
     633               0 :             *aSymbolEncoding = false;
     634               0 :             if (platformID > PLATFORM_ID_UNICODE || !aUVSTableOffset || *aUVSTableOffset) {
     635               0 :                 break; // we don't want to try anything else when this format is available.
     636                 :             }
     637               0 :         } else if (format == 14 && isUVSEncoding(platformID, encodingID) && aUVSTableOffset) {
     638               0 :             *aUVSTableOffset = offset;
     639               0 :             if (keepFormat == 12) {
     640               0 :                 break;
     641                 :             }
     642                 :         }
     643                 :     }
     644                 : 
     645               0 :     return keepFormat;
     646                 : }
     647                 : 
     648                 : nsresult
     649               0 : gfxFontUtils::ReadCMAP(const PRUint8 *aBuf, PRUint32 aBufLength,
     650                 :                        gfxSparseBitSet& aCharacterMap,
     651                 :                        PRUint32& aUVSOffset,
     652                 :                        bool& aUnicodeFont, bool& aSymbolFont)
     653                 : {
     654                 :     PRUint32 offset;
     655                 :     bool     symbol;
     656                 :     PRUint32 format = FindPreferredSubtable(aBuf, aBufLength,
     657               0 :                                             &offset, &aUVSOffset, &symbol);
     658                 : 
     659               0 :     if (format == 4) {
     660               0 :         if (symbol) {
     661               0 :             aUnicodeFont = false;
     662               0 :             aSymbolFont = true;
     663                 :         } else {
     664               0 :             aUnicodeFont = true;
     665               0 :             aSymbolFont = false;
     666                 :         }
     667                 :         return ReadCMAPTableFormat4(aBuf + offset, aBufLength - offset,
     668               0 :                                     aCharacterMap);
     669                 :     }
     670                 : 
     671               0 :     if (format == 12) {
     672               0 :         aUnicodeFont = true;
     673               0 :         aSymbolFont = false;
     674                 :         return ReadCMAPTableFormat12(aBuf + offset, aBufLength - offset,
     675               0 :                                      aCharacterMap);
     676                 :     }
     677                 : 
     678               0 :     return NS_ERROR_FAILURE;
     679                 : }
     680                 : 
     681                 : #pragma pack(1)
     682                 : 
     683                 : typedef struct {
     684                 :     AutoSwap_PRUint16 format;
     685                 :     AutoSwap_PRUint16 length;
     686                 :     AutoSwap_PRUint16 language;
     687                 :     AutoSwap_PRUint16 segCountX2;
     688                 :     AutoSwap_PRUint16 searchRange;
     689                 :     AutoSwap_PRUint16 entrySelector;
     690                 :     AutoSwap_PRUint16 rangeShift;
     691                 : 
     692                 :     AutoSwap_PRUint16 arrays[1];
     693                 : } Format4Cmap;
     694                 : 
     695                 : typedef struct {
     696                 :     AutoSwap_PRUint16 format;
     697                 :     AutoSwap_PRUint32 length;
     698                 :     AutoSwap_PRUint32 numVarSelectorRecords;
     699                 : 
     700                 :     typedef struct {
     701                 :         AutoSwap_PRUint24 varSelector;
     702                 :         AutoSwap_PRUint32 defaultUVSOffset;
     703                 :         AutoSwap_PRUint32 nonDefaultUVSOffset;
     704                 :     } VarSelectorRecord;
     705                 : 
     706                 :     VarSelectorRecord varSelectorRecords[1];
     707                 : } Format14Cmap;
     708                 : 
     709                 : typedef struct {
     710                 :     AutoSwap_PRUint32 numUVSMappings;
     711                 : 
     712                 :     typedef struct {
     713                 :         AutoSwap_PRUint24 unicodeValue;
     714                 :         AutoSwap_PRUint16 glyphID;
     715                 :     } UVSMapping;
     716                 : 
     717                 :     UVSMapping uvsMappings[1];
     718                 : } NonDefUVSTable;
     719                 : 
     720                 : #pragma pack()
     721                 : 
     722                 : PRUint32
     723               0 : gfxFontUtils::MapCharToGlyphFormat4(const PRUint8 *aBuf, PRUnichar aCh)
     724                 : {
     725               0 :     const Format4Cmap *cmap4 = reinterpret_cast<const Format4Cmap*>(aBuf);
     726                 :     PRUint16 segCount;
     727                 :     const AutoSwap_PRUint16 *endCodes;
     728                 :     const AutoSwap_PRUint16 *startCodes;
     729                 :     const AutoSwap_PRUint16 *idDelta;
     730                 :     const AutoSwap_PRUint16 *idRangeOffset;
     731                 :     PRUint16 probe;
     732                 :     PRUint16 rangeShiftOver2;
     733                 :     PRUint16 index;
     734                 : 
     735               0 :     segCount = (PRUint16)(cmap4->segCountX2) / 2;
     736                 : 
     737               0 :     endCodes = &cmap4->arrays[0];
     738               0 :     startCodes = &cmap4->arrays[segCount + 1]; // +1 for reserved word between arrays
     739               0 :     idDelta = &startCodes[segCount];
     740               0 :     idRangeOffset = &idDelta[segCount];
     741                 : 
     742               0 :     probe = 1 << (PRUint16)(cmap4->entrySelector);
     743               0 :     rangeShiftOver2 = (PRUint16)(cmap4->rangeShift) / 2;
     744                 : 
     745               0 :     if ((PRUint16)(startCodes[rangeShiftOver2]) <= aCh) {
     746               0 :         index = rangeShiftOver2;
     747                 :     } else {
     748               0 :         index = 0;
     749                 :     }
     750                 : 
     751               0 :     while (probe > 1) {
     752               0 :         probe >>= 1;
     753               0 :         if ((PRUint16)(startCodes[index + probe]) <= aCh) {
     754               0 :             index += probe;
     755                 :         }
     756                 :     }
     757                 : 
     758               0 :     if (aCh >= (PRUint16)(startCodes[index]) && aCh <= (PRUint16)(endCodes[index])) {
     759                 :         PRUint16 result;
     760               0 :         if ((PRUint16)(idRangeOffset[index]) == 0) {
     761               0 :             result = aCh;
     762                 :         } else {
     763               0 :             PRUint16 offset = aCh - (PRUint16)(startCodes[index]);
     764                 :             const AutoSwap_PRUint16 *glyphIndexTable =
     765                 :                 (const AutoSwap_PRUint16*)((const char*)&idRangeOffset[index] +
     766               0 :                                            (PRUint16)(idRangeOffset[index]));
     767               0 :             result = glyphIndexTable[offset];
     768                 :         }
     769                 : 
     770                 :         // note that this is unsigned 16-bit arithmetic, and may wrap around
     771               0 :         result += (PRUint16)(idDelta[index]);
     772               0 :         return result;
     773                 :     }
     774                 : 
     775               0 :     return 0;
     776                 : }
     777                 : 
     778                 : PRUint32
     779               0 : gfxFontUtils::MapCharToGlyphFormat12(const PRUint8 *aBuf, PRUint32 aCh)
     780                 : {
     781                 :     const Format12CmapHeader *cmap12 =
     782               0 :         reinterpret_cast<const Format12CmapHeader*>(aBuf);
     783                 : 
     784                 :     // We know that numGroups is within range for the subtable size
     785                 :     // because it was checked by ReadCMAPTableFormat12.
     786               0 :     PRUint32 numGroups = cmap12->numGroups;
     787                 : 
     788                 :     // The array of groups immediately follows the subtable header.
     789                 :     const Format12Group *groups =
     790               0 :         reinterpret_cast<const Format12Group*>(aBuf + sizeof(Format12CmapHeader));
     791                 : 
     792                 :     // For most efficient binary search, we want to work on a range that
     793                 :     // is a power of 2 so that we can always halve it by shifting.
     794                 :     // So we find the largest power of 2 that is <= numGroups.
     795                 :     // We will offset this range by rangeOffset so as to reach the end
     796                 :     // of the table, provided that doesn't put us beyond the target
     797                 :     // value from the outset.
     798               0 :     PRUint32 powerOf2 = mozilla::FindHighestBit(numGroups);
     799               0 :     PRUint32 rangeOffset = numGroups - powerOf2;
     800               0 :     PRUint32 range = 0;
     801                 :     PRUint32 startCharCode;
     802                 : 
     803               0 :     if (groups[rangeOffset].startCharCode <= aCh) {
     804               0 :         range = rangeOffset;
     805                 :     }
     806                 : 
     807                 :     // Repeatedly halve the size of the range until we find the target group
     808               0 :     while (powerOf2 > 1) {
     809               0 :         powerOf2 >>= 1;
     810               0 :         if (groups[range + powerOf2].startCharCode <= aCh) {
     811               0 :             range += powerOf2;
     812                 :         }
     813                 :     }
     814                 : 
     815                 :     // Check if the character is actually present in the range and return
     816                 :     // the corresponding glyph ID
     817               0 :     startCharCode = groups[range].startCharCode;
     818               0 :     if (startCharCode <= aCh && groups[range].endCharCode >= aCh) {
     819               0 :         return groups[range].startGlyphId + aCh - startCharCode;
     820                 :     }
     821                 : 
     822                 :     // Else it's not present, so return the .notdef glyph
     823               0 :     return 0;
     824                 : }
     825                 : 
     826                 : PRUint16
     827               0 : gfxFontUtils::MapUVSToGlyphFormat14(const PRUint8 *aBuf, PRUint32 aCh, PRUint32 aVS)
     828                 : {
     829               0 :     const Format14Cmap *cmap14 = reinterpret_cast<const Format14Cmap*>(aBuf);
     830                 : 
     831                 :     // binary search in varSelectorRecords
     832               0 :     PRUint32 min = 0;
     833               0 :     PRUint32 max = cmap14->numVarSelectorRecords;
     834               0 :     PRUint32 nonDefUVSOffset = 0;
     835               0 :     while (min < max) {
     836               0 :         PRUint32 index = (min + max) >> 1;
     837               0 :         PRUint32 varSelector = cmap14->varSelectorRecords[index].varSelector;
     838               0 :         if (aVS == varSelector) {
     839               0 :             nonDefUVSOffset = cmap14->varSelectorRecords[index].nonDefaultUVSOffset;
     840               0 :             break;
     841                 :         }
     842               0 :         if (aVS < varSelector) {
     843               0 :             max = index;
     844                 :         } else {
     845               0 :             min = index + 1;
     846                 :         }
     847                 :     }
     848               0 :     if (!nonDefUVSOffset) {
     849               0 :         return 0;
     850                 :     }
     851                 : 
     852                 :     const NonDefUVSTable *table = reinterpret_cast<const NonDefUVSTable*>
     853               0 :                                       (aBuf + nonDefUVSOffset);
     854                 : 
     855                 :     // binary search in uvsMappings
     856               0 :     min = 0;
     857               0 :     max = table->numUVSMappings;
     858               0 :     while (min < max) {
     859               0 :         PRUint32 index = (min + max) >> 1;
     860               0 :         PRUint32 unicodeValue = table->uvsMappings[index].unicodeValue;
     861               0 :         if (aCh == unicodeValue) {
     862               0 :             return table->uvsMappings[index].glyphID;
     863                 :         }
     864               0 :         if (aCh < unicodeValue) {
     865               0 :             max = index;
     866                 :         } else {
     867               0 :             min = index + 1;
     868                 :         }
     869                 :     }
     870                 : 
     871               0 :     return 0;
     872                 : }
     873                 : 
     874                 : PRUint32
     875               0 : gfxFontUtils::MapCharToGlyph(const PRUint8 *aBuf, PRUint32 aBufLength,
     876                 :                              PRUint32 aCh)
     877                 : {
     878                 :     PRUint32 offset;
     879                 :     bool     symbol;
     880                 :     PRUint32 format = FindPreferredSubtable(aBuf, aBufLength, &offset,
     881               0 :                                             nsnull, &symbol);
     882                 : 
     883               0 :     switch (format) {
     884                 :     case 4:
     885                 :         return aCh < UNICODE_BMP_LIMIT ?
     886               0 :             MapCharToGlyphFormat4(aBuf + offset, PRUnichar(aCh)) : 0;
     887                 :     case 12:
     888               0 :         return MapCharToGlyphFormat12(aBuf + offset, aCh);
     889                 :     default:
     890               0 :         return 0;
     891                 :     }
     892                 : }
     893                 : 
     894               0 : PRUint8 gfxFontUtils::CharRangeBit(PRUint32 ch) {
     895               0 :     const PRUint32 n = sizeof(gUnicodeRanges) / sizeof(struct UnicodeRangeTableEntry);
     896                 : 
     897               0 :     for (PRUint32 i = 0; i < n; ++i)
     898               0 :         if (ch >= gUnicodeRanges[i].start && ch <= gUnicodeRanges[i].end)
     899               0 :             return gUnicodeRanges[i].bit;
     900                 : 
     901               0 :     return NO_RANGE_FOUND;
     902                 : }
     903                 : 
     904               0 : void gfxFontUtils::GetPrefsFontList(const char *aPrefName, nsTArray<nsString>& aFontList)
     905                 : {
     906               0 :     const PRUnichar kComma = PRUnichar(',');
     907                 :     
     908               0 :     aFontList.Clear();
     909                 :     
     910                 :     // get the list of single-face font families
     911               0 :     nsAdoptingString fontlistValue = Preferences::GetString(aPrefName);
     912               0 :     if (!fontlistValue) {
     913                 :         return;
     914                 :     }
     915                 : 
     916                 :     // append each font name to the list
     917               0 :     nsAutoString fontname;
     918                 :     const PRUnichar *p, *p_end;
     919               0 :     fontlistValue.BeginReading(p);
     920               0 :     fontlistValue.EndReading(p_end);
     921                 : 
     922               0 :      while (p < p_end) {
     923               0 :         const PRUnichar *nameStart = p;
     924               0 :         while (++p != p_end && *p != kComma)
     925                 :         /* nothing */ ;
     926                 : 
     927                 :         // pull out a single name and clean out leading/trailing whitespace        
     928               0 :         fontname = Substring(nameStart, p);
     929               0 :         fontname.CompressWhitespace(true, true);
     930                 :         
     931                 :         // append it to the list
     932               0 :         aFontList.AppendElement(fontname);
     933               0 :         ++p;
     934                 :     }
     935                 : 
     936                 : }
     937                 : 
     938                 : // produce a unique font name that is (1) a valid Postscript name and (2) less
     939                 : // than 31 characters in length.  Using AddFontMemResourceEx on Windows fails 
     940                 : // for names longer than 30 characters in length.
     941                 : 
     942                 : #define MAX_B64_LEN 32
     943                 : 
     944               0 : nsresult gfxFontUtils::MakeUniqueUserFontName(nsAString& aName)
     945                 : {
     946                 :     nsCOMPtr<nsIUUIDGenerator> uuidgen =
     947               0 :       do_GetService("@mozilla.org/uuid-generator;1");
     948               0 :     NS_ENSURE_TRUE(uuidgen, NS_ERROR_OUT_OF_MEMORY);
     949                 : 
     950                 :     nsID guid;
     951                 : 
     952                 :     NS_ASSERTION(sizeof(guid) * 2 <= MAX_B64_LEN, "size of nsID has changed!");
     953                 : 
     954               0 :     nsresult rv = uuidgen->GenerateUUIDInPlace(&guid);
     955               0 :     NS_ENSURE_SUCCESS(rv, rv);
     956                 : 
     957               0 :     char guidB64[MAX_B64_LEN] = {0};
     958                 : 
     959               0 :     if (!PL_Base64Encode(reinterpret_cast<char*>(&guid), sizeof(guid), guidB64))
     960               0 :         return NS_ERROR_FAILURE;
     961                 : 
     962                 :     // all b64 characters except for '/' are allowed in Postscript names, so convert / ==> -
     963                 :     char *p;
     964               0 :     for (p = guidB64; *p; p++) {
     965               0 :         if (*p == '/')
     966               0 :             *p = '-';
     967                 :     }
     968                 : 
     969               0 :     aName.Assign(NS_LITERAL_STRING("uf"));
     970               0 :     aName.AppendASCII(guidB64);
     971               0 :     return NS_OK;
     972                 : }
     973                 : 
     974                 : 
     975                 : // TrueType/OpenType table handling code
     976                 : 
     977                 : // need byte aligned structs
     978                 : #pragma pack(1)
     979                 : 
     980                 : // name table stores set of name record structures, followed by
     981                 : // large block containing all the strings.  name record offset and length
     982                 : // indicates the offset and length within that block.
     983                 : // http://www.microsoft.com/typography/otspec/name.htm
     984                 : struct NameRecordData {
     985                 :     PRUint32  offset;
     986                 :     PRUint32  length;
     987                 : };
     988                 : 
     989                 : #pragma pack()
     990                 : 
     991                 : static bool
     992               0 : IsValidSFNTVersion(PRUint32 version)
     993                 : {
     994                 :     // normally 0x00010000, CFF-style OT fonts == 'OTTO' and Apple TT fonts = 'true'
     995                 :     // 'typ1' is also possible for old Type 1 fonts in a SFNT container but not supported
     996                 :     return version == 0x10000 ||
     997                 :            version == TRUETYPE_TAG('O','T','T','O') ||
     998               0 :            version == TRUETYPE_TAG('t','r','u','e');
     999                 : }
    1000                 : 
    1001                 : // copy and swap UTF-16 values, assume no surrogate pairs, can be in place
    1002                 : static void
    1003               0 : CopySwapUTF16(const PRUint16 *aInBuf, PRUint16 *aOutBuf, PRUint32 aLen)
    1004                 : {
    1005               0 :     const PRUint16 *end = aInBuf + aLen;
    1006               0 :     while (aInBuf < end) {
    1007               0 :         PRUint16 value = *aInBuf;
    1008               0 :         *aOutBuf = (value >> 8) | (value & 0xff) << 8;
    1009               0 :         aOutBuf++;
    1010               0 :         aInBuf++;
    1011                 :     }
    1012               0 : }
    1013                 : 
    1014                 : static bool
    1015               0 : ValidateKernTable(const PRUint8 *aKernTable, PRUint32 aKernLength)
    1016                 : {
    1017                 :     // -- kern table can cause crashes if invalid, so do some basic sanity-checking
    1018               0 :     const KernTableVersion0 *kernTable0 = reinterpret_cast<const KernTableVersion0*>(aKernTable);
    1019               0 :     if (aKernLength < sizeof(KernTableVersion0)) {
    1020               0 :         return false;
    1021                 :     }
    1022               0 :     if (PRUint16(kernTable0->version) == 0) {
    1023               0 :         if (aKernLength < sizeof(KernTableVersion0) +
    1024               0 :                             PRUint16(kernTable0->nTables) * sizeof(KernTableSubtableHeaderVersion0)) {
    1025               0 :             return false;
    1026                 :         }
    1027                 :         // at least the table is big enough to contain the subtable headers;
    1028                 :         // we could go further and check the actual subtable sizes....
    1029                 :         // for now, assume this is OK
    1030               0 :         return true;
    1031                 :     }
    1032                 : 
    1033               0 :     const KernTableVersion1 *kernTable1 = reinterpret_cast<const KernTableVersion1*>(aKernTable);
    1034               0 :     if (aKernLength < sizeof(KernTableVersion1)) {
    1035               0 :         return false;
    1036                 :     }
    1037               0 :     if (kernTable1->version == 0x00010000) {
    1038               0 :         if (aKernLength < sizeof(KernTableVersion1) +
    1039               0 :                             kernTable1->nTables * sizeof(KernTableSubtableHeaderVersion1)) {
    1040               0 :             return false;
    1041                 :         }
    1042                 :         // at least the table is big enough to contain the subtable headers;
    1043                 :         // we could go further and check the actual subtable sizes....
    1044                 :         // for now, assume this is OK
    1045               0 :         return true;
    1046                 :     }
    1047                 : 
    1048                 :     // neither the old Windows version nor the newer Apple one; refuse to use it
    1049               0 :     return false;
    1050                 : }
    1051                 : 
    1052                 : static bool
    1053               0 : ValidateLocaTable(const PRUint8* aLocaTable, PRUint32 aLocaLen,
    1054                 :                   PRUint32 aGlyfLen, PRInt16 aLocaFormat, PRUint16 aNumGlyphs)
    1055                 : {
    1056               0 :     if (aLocaFormat == 0) {
    1057               0 :         if (aLocaLen < PRUint32(aNumGlyphs + 1) * sizeof(PRUint16)) {
    1058               0 :             return false;
    1059                 :         }
    1060                 :         const AutoSwap_PRUint16 *p =
    1061               0 :             reinterpret_cast<const AutoSwap_PRUint16*>(aLocaTable);
    1062               0 :         PRUint32 prev = 0;
    1063               0 :         for (PRUint32 i = 0; i <= aNumGlyphs; ++i) {
    1064               0 :             PRUint32 current = PRUint16(*p++) * 2;
    1065               0 :             if (current < prev || current > aGlyfLen) {
    1066               0 :                 return false;
    1067                 :             }
    1068               0 :             prev = current;
    1069                 :         }
    1070               0 :         return true;
    1071                 :     }
    1072               0 :     if (aLocaFormat == 1) {
    1073               0 :         if (aLocaLen < (aNumGlyphs + 1) * sizeof(PRUint32)) {
    1074               0 :             return false;
    1075                 :         }
    1076                 :         const AutoSwap_PRUint32 *p =
    1077               0 :             reinterpret_cast<const AutoSwap_PRUint32*>(aLocaTable);
    1078               0 :         PRUint32 prev = 0;
    1079               0 :         for (PRUint32 i = 0; i <= aNumGlyphs; ++i) {
    1080               0 :             PRUint32 current = *p++;
    1081               0 :             if (current < prev || current > aGlyfLen) {
    1082               0 :                 return false;
    1083                 :             }
    1084               0 :             prev = current;
    1085                 :         }
    1086               0 :         return true;
    1087                 :     }
    1088               0 :     return false;
    1089                 : }
    1090                 : 
    1091                 : gfxUserFontType
    1092               0 : gfxFontUtils::DetermineFontDataType(const PRUint8 *aFontData, PRUint32 aFontDataLength)
    1093                 : {
    1094                 :     // test for OpenType font data
    1095                 :     // problem: EOT-Lite with 0x10000 length will look like TrueType!
    1096               0 :     if (aFontDataLength >= sizeof(SFNTHeader)) {
    1097               0 :         const SFNTHeader *sfntHeader = reinterpret_cast<const SFNTHeader*>(aFontData);
    1098               0 :         PRUint32 sfntVersion = sfntHeader->sfntVersion;
    1099               0 :         if (IsValidSFNTVersion(sfntVersion)) {
    1100               0 :             return GFX_USERFONT_OPENTYPE;
    1101                 :         }
    1102                 :     }
    1103                 :     
    1104                 :     // test for WOFF
    1105               0 :     if (aFontDataLength >= sizeof(AutoSwap_PRUint32)) {
    1106                 :         const AutoSwap_PRUint32 *version = 
    1107               0 :             reinterpret_cast<const AutoSwap_PRUint32*>(aFontData);
    1108               0 :         if (PRUint32(*version) == TRUETYPE_TAG('w','O','F','F')) {
    1109               0 :             return GFX_USERFONT_WOFF;
    1110                 :         }
    1111                 :     }
    1112                 :     
    1113                 :     // tests for other formats here
    1114                 :     
    1115               0 :     return GFX_USERFONT_UNKNOWN;
    1116                 : }
    1117                 : 
    1118                 : bool
    1119               0 : gfxFontUtils::ValidateSFNTHeaders(const PRUint8 *aFontData, 
    1120                 :                                   PRUint32 aFontDataLength)
    1121                 : {
    1122               0 :     NS_ASSERTION(aFontData, "null font data");
    1123                 : 
    1124               0 :     PRUint64 dataLength(aFontDataLength);
    1125                 :     
    1126                 :     // read in the sfnt header
    1127               0 :     if (sizeof(SFNTHeader) > aFontDataLength) {
    1128               0 :         NS_WARNING("invalid font (insufficient data)");
    1129               0 :         return false;
    1130                 :     }
    1131                 :     
    1132               0 :     const SFNTHeader *sfntHeader = reinterpret_cast<const SFNTHeader*>(aFontData);
    1133               0 :     PRUint32 sfntVersion = sfntHeader->sfntVersion;
    1134               0 :     if (!IsValidSFNTVersion(sfntVersion)) {
    1135               0 :         NS_WARNING("invalid font (SFNT version)");
    1136               0 :         return false;
    1137                 :     }
    1138                 :     
    1139                 :     // iterate through the table headers to find the head, name and OS/2 tables
    1140               0 :     bool foundHead = false, foundOS2 = false, foundName = false;
    1141               0 :     bool foundGlyphs = false, foundCFF = false, foundKern = false;
    1142               0 :     bool foundLoca = false, foundMaxp = false;
    1143               0 :     PRUint32 headOffset = 0, headLen, nameOffset = 0, nameLen, kernOffset = 0,
    1144               0 :         kernLen = 0, glyfLen = 0, locaOffset = 0, locaLen = 0,
    1145               0 :         maxpOffset = 0, maxpLen;
    1146                 :     PRUint32 i, numTables;
    1147                 : 
    1148               0 :     numTables = sfntHeader->numTables;
    1149               0 :     PRUint32 headerLen = sizeof(SFNTHeader) + sizeof(TableDirEntry) * numTables;
    1150               0 :     if (headerLen > aFontDataLength) {
    1151               0 :         NS_WARNING("invalid font (table directory)");
    1152               0 :         return false;
    1153                 :     }
    1154                 :     
    1155                 :     // table directory entries begin immediately following SFNT header
    1156                 :     const TableDirEntry *dirEntry = 
    1157               0 :         reinterpret_cast<const TableDirEntry*>(aFontData + sizeof(SFNTHeader));
    1158               0 :     PRUint32 checksum = 0;
    1159                 :     
    1160                 :     // checksum for font = (checksum of header) + (checksum of tables)
    1161                 :     const AutoSwap_PRUint32 *headerData = 
    1162               0 :         reinterpret_cast<const AutoSwap_PRUint32*>(aFontData);
    1163                 : 
    1164                 :     // header length is in bytes, checksum calculated in longwords
    1165               0 :     for (i = 0; i < (headerLen >> 2); i++, headerData++) {
    1166               0 :         checksum += *headerData;
    1167                 :     }
    1168                 :     
    1169               0 :     for (i = 0; i < numTables; i++, dirEntry++) {
    1170                 :     
    1171                 :         // sanity check on offset, length values
    1172               0 :         if (PRUint64(dirEntry->offset) + PRUint64(dirEntry->length) > dataLength) {
    1173               0 :             NS_WARNING("invalid font (table directory entry)");
    1174               0 :             return false;
    1175                 :         }
    1176                 : 
    1177               0 :         checksum += dirEntry->checkSum;
    1178                 :         
    1179               0 :         switch (dirEntry->tag) {
    1180                 : 
    1181                 :         case TRUETYPE_TAG('h','e','a','d'):
    1182               0 :             foundHead = true;
    1183               0 :             headOffset = dirEntry->offset;
    1184               0 :             headLen = dirEntry->length;
    1185               0 :             if (headLen < sizeof(HeadTable)) {
    1186               0 :                 NS_WARNING("invalid font (head table length)");
    1187               0 :                 return false;
    1188                 :             }
    1189               0 :             break;
    1190                 : 
    1191                 :         case TRUETYPE_TAG('k','e','r','n'):
    1192               0 :             foundKern = true;
    1193               0 :             kernOffset = dirEntry->offset;
    1194               0 :             kernLen = dirEntry->length;
    1195               0 :             break;
    1196                 : 
    1197                 :         case TRUETYPE_TAG('n','a','m','e'):
    1198               0 :             foundName = true;
    1199               0 :             nameOffset = dirEntry->offset;
    1200               0 :             nameLen = dirEntry->length;
    1201               0 :             break;
    1202                 : 
    1203                 :         case TRUETYPE_TAG('O','S','/','2'):
    1204               0 :             foundOS2 = true;
    1205               0 :             break;
    1206                 : 
    1207                 :         case TRUETYPE_TAG('g','l','y','f'):  // TrueType-style quadratic glyph table
    1208               0 :             foundGlyphs = true;
    1209               0 :             glyfLen = dirEntry->length;
    1210               0 :             break;
    1211                 : 
    1212                 :         case TRUETYPE_TAG('l','o','c','a'):  // glyph location table
    1213               0 :             foundLoca = true;
    1214               0 :             locaOffset = dirEntry->offset;
    1215               0 :             locaLen = dirEntry->length;
    1216               0 :             break;
    1217                 : 
    1218                 :         case TRUETYPE_TAG('m','a','x','p'):  // max profile
    1219               0 :             foundMaxp = true;
    1220               0 :             maxpOffset = dirEntry->offset;
    1221               0 :             maxpLen = dirEntry->length;
    1222               0 :             if (maxpLen < sizeof(MaxpTableHeader)) {
    1223               0 :                 NS_WARNING("invalid font (maxp table length)");
    1224               0 :                 return false;
    1225                 :             }
    1226               0 :             break;
    1227                 : 
    1228                 :         case TRUETYPE_TAG('C','F','F',' '):  // PS-style cubic glyph table
    1229               0 :             foundCFF = true;
    1230               0 :             break;
    1231                 : 
    1232                 :         default:
    1233               0 :             break;
    1234                 :         }
    1235                 : 
    1236                 :     }
    1237                 : 
    1238                 :     // simple sanity checks
    1239                 :     
    1240                 :     // -- fonts need head, name, maxp tables
    1241               0 :     if (!foundHead || !foundName || !foundMaxp) {
    1242               0 :         NS_WARNING("invalid font (missing head/name/maxp table)");
    1243               0 :         return false;
    1244                 :     }
    1245                 :     
    1246                 :     // -- on Windows need OS/2 table
    1247                 : #ifdef XP_WIN
    1248                 :     if (!foundOS2) {
    1249                 :         NS_WARNING("invalid font (missing OS/2 table)");
    1250                 :         return false;
    1251                 :     }
    1252                 : #endif
    1253                 : 
    1254                 :     // -- head table data
    1255               0 :     const HeadTable *headData = reinterpret_cast<const HeadTable*>(aFontData + headOffset);
    1256                 : 
    1257               0 :     if (headData->tableVersionNumber != HeadTable::HEAD_VERSION) {
    1258               0 :         NS_WARNING("invalid font (head table version)");
    1259               0 :         return false;
    1260                 :     }
    1261                 : 
    1262               0 :     if (headData->magicNumber != HeadTable::HEAD_MAGIC_NUMBER) {
    1263               0 :         NS_WARNING("invalid font (head magic number)");
    1264               0 :         return false;
    1265                 :     }
    1266                 : 
    1267               0 :     if (headData->checkSumAdjustment != (HeadTable::HEAD_CHECKSUM_CALC_CONST - checksum)) {
    1268               0 :         NS_WARNING("invalid font (bad checksum)");
    1269                 :         // Bug 483459 - warn about a bad checksum but allow the font to be 
    1270                 :         // used, since a small percentage of fonts don't calculate this 
    1271                 :         // correctly and font systems aren't fussy about this
    1272                 :         // return false;
    1273                 :     }
    1274                 :     
    1275                 :     // need glyf or CFF table based on sfnt version
    1276               0 :     if (sfntVersion == TRUETYPE_TAG('O','T','T','O')) {
    1277               0 :         if (!foundCFF) {
    1278               0 :             NS_WARNING("invalid font (missing CFF table)");
    1279               0 :             return false;
    1280                 :         }
    1281                 :     } else {
    1282               0 :         if (!foundGlyphs || !foundLoca) {
    1283               0 :             NS_WARNING("invalid font (missing glyf or loca table)");
    1284               0 :             return false;
    1285                 :         }
    1286                 : 
    1287                 :         // sanity-check 'loca' offsets
    1288                 :         const MaxpTableHeader *maxpData =
    1289               0 :             reinterpret_cast<const MaxpTableHeader*>(aFontData + maxpOffset);
    1290               0 :         if (!ValidateLocaTable(aFontData + locaOffset, locaLen, glyfLen,
    1291                 :                                headData->indexToLocFormat,
    1292               0 :                                maxpData->numGlyphs)) {
    1293               0 :             NS_WARNING("invalid font (loca table offsets)");
    1294               0 :             return false;
    1295                 :         }
    1296                 :     }
    1297                 :     
    1298                 :     // -- name table data
    1299               0 :     const NameHeader *nameHeader = reinterpret_cast<const NameHeader*>(aFontData + nameOffset);
    1300                 : 
    1301               0 :     PRUint32 nameCount = nameHeader->count;
    1302                 : 
    1303                 :     // -- sanity check the number of name records
    1304               0 :     if (PRUint64(nameCount) * sizeof(NameRecord) + PRUint64(nameOffset) > dataLength) {
    1305               0 :         NS_WARNING("invalid font (name records)");
    1306               0 :         return false;
    1307                 :     }
    1308                 :     
    1309                 :     // -- iterate through name records
    1310                 :     const NameRecord *nameRecord = reinterpret_cast<const NameRecord*>
    1311               0 :                                        (aFontData + nameOffset + sizeof(NameHeader));
    1312               0 :     PRUint64 nameStringsBase = PRUint64(nameOffset) + PRUint64(nameHeader->stringOffset);
    1313                 : 
    1314               0 :     for (i = 0; i < nameCount; i++, nameRecord++) {
    1315               0 :         PRUint32 namelen = nameRecord->length;
    1316               0 :         PRUint32 nameoff = nameRecord->offset;  // offset from base of string storage
    1317                 : 
    1318               0 :         if (nameStringsBase + PRUint64(nameoff) + PRUint64(namelen) > dataLength) {
    1319               0 :             NS_WARNING("invalid font (name table strings)");
    1320               0 :             return false;
    1321                 :         }
    1322                 :     }
    1323                 : 
    1324                 :     // -- sanity-check the kern table, if present (see bug 487549)
    1325               0 :     if (foundKern) {
    1326               0 :         if (!ValidateKernTable(aFontData + kernOffset, kernLen)) {
    1327               0 :             NS_WARNING("invalid font (kern table)");
    1328               0 :             return false;
    1329                 :         }
    1330                 :     }
    1331                 : 
    1332                 :     // everything seems consistent
    1333               0 :     return true;
    1334                 : }
    1335                 : 
    1336                 : nsresult
    1337               0 : gfxFontUtils::RenameFont(const nsAString& aName, const PRUint8 *aFontData, 
    1338                 :                          PRUint32 aFontDataLength, FallibleTArray<PRUint8> *aNewFont)
    1339                 : {
    1340               0 :     NS_ASSERTION(aNewFont, "null font data array");
    1341                 :     
    1342               0 :     PRUint64 dataLength(aFontDataLength);
    1343                 : 
    1344                 :     // new name table
    1345                 :     static const PRUint32 neededNameIDs[] = {NAME_ID_FAMILY, 
    1346                 :                                              NAME_ID_STYLE,
    1347                 :                                              NAME_ID_UNIQUE,
    1348                 :                                              NAME_ID_FULL,
    1349                 :                                              NAME_ID_POSTSCRIPT};
    1350                 : 
    1351                 :     // calculate new name table size
    1352               0 :     PRUint16 nameCount = ArrayLength(neededNameIDs);
    1353                 : 
    1354                 :     // leave room for null-terminator
    1355               0 :     PRUint16 nameStrLength = (aName.Length() + 1) * sizeof(PRUnichar); 
    1356                 : 
    1357                 :     // round name table size up to 4-byte multiple
    1358                 :     PRUint32 nameTableSize = (sizeof(NameHeader) +
    1359                 :                               sizeof(NameRecord) * nameCount +
    1360                 :                               nameStrLength +
    1361               0 :                               3) & ~3;
    1362                 :                               
    1363               0 :     if (dataLength + nameTableSize > PR_UINT32_MAX)
    1364               0 :         return NS_ERROR_FAILURE;
    1365                 :         
    1366                 :     // bug 505386 - need to handle unpadded font length
    1367               0 :     PRUint32 paddedFontDataSize = (aFontDataLength + 3) & ~3;
    1368               0 :     PRUint32 adjFontDataSize = paddedFontDataSize + nameTableSize;
    1369                 : 
    1370                 :     // create new buffer: old font data plus new name table
    1371               0 :     if (!aNewFont->AppendElements(adjFontDataSize))
    1372               0 :         return NS_ERROR_OUT_OF_MEMORY;
    1373                 : 
    1374                 :     // copy the old font data
    1375               0 :     PRUint8 *newFontData = reinterpret_cast<PRUint8*>(aNewFont->Elements());
    1376                 :     
    1377                 :     // null the last four bytes in case the font length is not a multiple of 4
    1378               0 :     memset(newFontData + aFontDataLength, 0, paddedFontDataSize - aFontDataLength);
    1379                 : 
    1380                 :     // copy font data
    1381               0 :     memcpy(newFontData, aFontData, aFontDataLength);
    1382                 :     
    1383                 :     // null out the last 4 bytes for checksum calculations
    1384               0 :     memset(newFontData + adjFontDataSize - 4, 0, 4);
    1385                 :     
    1386                 :     NameHeader *nameHeader = reinterpret_cast<NameHeader*>(newFontData +
    1387               0 :                                                             paddedFontDataSize);
    1388                 :     
    1389                 :     // -- name header
    1390               0 :     nameHeader->format = 0;
    1391               0 :     nameHeader->count = nameCount;
    1392               0 :     nameHeader->stringOffset = sizeof(NameHeader) + nameCount * sizeof(NameRecord);
    1393                 :     
    1394                 :     // -- name records
    1395                 :     PRUint32 i;
    1396               0 :     NameRecord *nameRecord = reinterpret_cast<NameRecord*>(nameHeader + 1);
    1397                 :     
    1398               0 :     for (i = 0; i < nameCount; i++, nameRecord++) {
    1399               0 :         nameRecord->platformID = PLATFORM_ID_MICROSOFT;
    1400               0 :         nameRecord->encodingID = ENCODING_ID_MICROSOFT_UNICODEBMP;
    1401               0 :         nameRecord->languageID = LANG_ID_MICROSOFT_EN_US;
    1402               0 :         nameRecord->nameID = neededNameIDs[i];
    1403               0 :         nameRecord->offset = 0;
    1404               0 :         nameRecord->length = nameStrLength;
    1405                 :     }
    1406                 :     
    1407                 :     // -- string data, located after the name records, stored in big-endian form
    1408               0 :     PRUnichar *strData = reinterpret_cast<PRUnichar*>(nameRecord);
    1409                 : 
    1410               0 :     const PRUnichar *nameStr = aName.BeginReading();
    1411               0 :     const PRUnichar *nameStrEnd = aName.EndReading();
    1412               0 :     while (nameStr < nameStrEnd) {
    1413               0 :         PRUnichar ch = *nameStr++;
    1414               0 :         *strData++ = NS_SWAP16(ch);
    1415                 :     }
    1416               0 :     *strData = 0; // add null termination
    1417                 :     
    1418                 :     // adjust name table header to point to the new name table
    1419               0 :     SFNTHeader *sfntHeader = reinterpret_cast<SFNTHeader*>(newFontData);
    1420                 : 
    1421                 :     // table directory entries begin immediately following SFNT header
    1422                 :     TableDirEntry *dirEntry = 
    1423               0 :         reinterpret_cast<TableDirEntry*>(newFontData + sizeof(SFNTHeader));
    1424                 : 
    1425               0 :     PRUint32 numTables = sfntHeader->numTables;
    1426               0 :     bool foundName = false;
    1427                 :     
    1428               0 :     for (i = 0; i < numTables; i++, dirEntry++) {
    1429               0 :         if (dirEntry->tag == TRUETYPE_TAG('n','a','m','e')) {
    1430               0 :             foundName = true;
    1431               0 :             break;
    1432                 :         }
    1433                 :     }
    1434                 :     
    1435                 :     // function only called if font validates, so this should always be true
    1436               0 :     NS_ASSERTION(foundName, "attempt to rename font with no name table");
    1437                 : 
    1438                 :     // note: dirEntry now points to name record
    1439                 :     
    1440                 :     // recalculate name table checksum
    1441               0 :     PRUint32 checkSum = 0;
    1442               0 :     AutoSwap_PRUint32 *nameData = reinterpret_cast<AutoSwap_PRUint32*> (nameHeader);
    1443               0 :     AutoSwap_PRUint32 *nameDataEnd = nameData + (nameTableSize >> 2);
    1444                 :     
    1445               0 :     while (nameData < nameDataEnd)
    1446               0 :         checkSum = checkSum + *nameData++;
    1447                 :     
    1448                 :     // adjust name table entry to point to new name table
    1449               0 :     dirEntry->offset = paddedFontDataSize;
    1450               0 :     dirEntry->length = nameTableSize;
    1451               0 :     dirEntry->checkSum = checkSum;
    1452                 :     
    1453                 :     // fix up checksums
    1454               0 :     PRUint32 checksum = 0;
    1455                 :     
    1456                 :     // checksum for font = (checksum of header) + (checksum of tables)
    1457               0 :     PRUint32 headerLen = sizeof(SFNTHeader) + sizeof(TableDirEntry) * numTables;
    1458                 :     const AutoSwap_PRUint32 *headerData = 
    1459               0 :         reinterpret_cast<const AutoSwap_PRUint32*>(newFontData);
    1460                 : 
    1461                 :     // header length is in bytes, checksum calculated in longwords
    1462               0 :     for (i = 0; i < (headerLen >> 2); i++, headerData++) {
    1463               0 :         checksum += *headerData;
    1464                 :     }
    1465                 :     
    1466               0 :     PRUint32 headOffset = 0;
    1467               0 :     dirEntry = reinterpret_cast<TableDirEntry*>(newFontData + sizeof(SFNTHeader));
    1468                 : 
    1469               0 :     for (i = 0; i < numTables; i++, dirEntry++) {
    1470               0 :         if (dirEntry->tag == TRUETYPE_TAG('h','e','a','d')) {
    1471               0 :             headOffset = dirEntry->offset;
    1472                 :         }
    1473               0 :         checksum += dirEntry->checkSum;
    1474                 :     }
    1475                 :     
    1476               0 :     NS_ASSERTION(headOffset != 0, "no head table for font");
    1477                 :     
    1478               0 :     HeadTable *headData = reinterpret_cast<HeadTable*>(newFontData + headOffset);
    1479                 : 
    1480               0 :     headData->checkSumAdjustment = HeadTable::HEAD_CHECKSUM_CALC_CONST - checksum;
    1481                 : 
    1482               0 :     return NS_OK;
    1483                 : }
    1484                 : 
    1485                 : // This is only called after the basic validity of the downloaded sfnt
    1486                 : // data has been checked, so it should never fail to find the name table
    1487                 : // (though it might fail to read it, if memory isn't available);
    1488                 : // other checks here are just for extra paranoia.
    1489                 : nsresult
    1490               0 : gfxFontUtils::GetFullNameFromSFNT(const PRUint8* aFontData, PRUint32 aLength,
    1491                 :                                   nsAString& aFullName)
    1492                 : {
    1493               0 :     aFullName.AssignLiteral("(MISSING NAME)"); // should always get replaced
    1494                 : 
    1495               0 :     NS_ENSURE_TRUE(aLength >= sizeof(SFNTHeader), NS_ERROR_UNEXPECTED);
    1496                 :     const SFNTHeader *sfntHeader =
    1497               0 :         reinterpret_cast<const SFNTHeader*>(aFontData);
    1498                 :     const TableDirEntry *dirEntry =
    1499               0 :         reinterpret_cast<const TableDirEntry*>(aFontData + sizeof(SFNTHeader));
    1500               0 :     PRUint32 numTables = sfntHeader->numTables;
    1501               0 :     NS_ENSURE_TRUE(aLength >=
    1502                 :                    sizeof(SFNTHeader) + numTables * sizeof(TableDirEntry),
    1503                 :                    NS_ERROR_UNEXPECTED);
    1504               0 :     bool foundName = false;
    1505               0 :     for (PRUint32 i = 0; i < numTables; i++, dirEntry++) {
    1506               0 :         if (dirEntry->tag == TRUETYPE_TAG('n','a','m','e')) {
    1507               0 :             foundName = true;
    1508               0 :             break;
    1509                 :         }
    1510                 :     }
    1511                 :     
    1512                 :     // should never fail, as we're only called after font validation succeeded
    1513               0 :     NS_ENSURE_TRUE(foundName, NS_ERROR_NOT_AVAILABLE);
    1514                 : 
    1515               0 :     PRUint32 len = dirEntry->length;
    1516               0 :     NS_ENSURE_TRUE(aLength > len && aLength - len >= dirEntry->offset,
    1517                 :                    NS_ERROR_UNEXPECTED);
    1518               0 :     FallibleTArray<PRUint8> nameTable;
    1519               0 :     if (!nameTable.SetLength(len)) {
    1520               0 :         return NS_ERROR_OUT_OF_MEMORY;
    1521                 :     }
    1522               0 :     memcpy(nameTable.Elements(), aFontData + dirEntry->offset, len);
    1523                 : 
    1524               0 :     return GetFullNameFromTable(nameTable, aFullName);
    1525                 : }
    1526                 : 
    1527                 : nsresult
    1528               0 : gfxFontUtils::GetFullNameFromTable(FallibleTArray<PRUint8>& aNameTable,
    1529                 :                                    nsAString& aFullName)
    1530                 : {
    1531               0 :     nsAutoString name;
    1532                 :     nsresult rv =
    1533                 :         gfxFontUtils::ReadCanonicalName(aNameTable,
    1534                 :                                         gfxFontUtils::NAME_ID_FULL,
    1535               0 :                                         name);
    1536               0 :     if (NS_SUCCEEDED(rv) && !name.IsEmpty()) {
    1537               0 :         aFullName = name;
    1538               0 :         return NS_OK;
    1539                 :     }
    1540                 :     rv = gfxFontUtils::ReadCanonicalName(aNameTable,
    1541                 :                                          gfxFontUtils::NAME_ID_FAMILY,
    1542               0 :                                          name);
    1543               0 :     if (NS_SUCCEEDED(rv) && !name.IsEmpty()) {
    1544               0 :         nsAutoString styleName;
    1545                 :         rv = gfxFontUtils::ReadCanonicalName(aNameTable,
    1546                 :                                              gfxFontUtils::NAME_ID_STYLE,
    1547               0 :                                              styleName);
    1548               0 :         if (NS_SUCCEEDED(rv) && !styleName.IsEmpty()) {
    1549               0 :             name.AppendLiteral(" ");
    1550               0 :             name.Append(styleName);
    1551               0 :             aFullName = name;
    1552                 :         }
    1553               0 :         return NS_OK;
    1554                 :     }
    1555                 : 
    1556               0 :     return NS_ERROR_NOT_AVAILABLE;
    1557                 : }
    1558                 : 
    1559                 : enum {
    1560                 : #if defined(XP_MACOSX)
    1561                 :     CANONICAL_LANG_ID = gfxFontUtils::LANG_ID_MAC_ENGLISH,
    1562                 :     PLATFORM_ID       = gfxFontUtils::PLATFORM_ID_MAC
    1563                 : #else
    1564                 :     CANONICAL_LANG_ID = gfxFontUtils::LANG_ID_MICROSOFT_EN_US,
    1565                 :     PLATFORM_ID       = gfxFontUtils::PLATFORM_ID_MICROSOFT
    1566                 : #endif
    1567                 : };    
    1568                 : 
    1569                 : nsresult
    1570               0 : gfxFontUtils::ReadNames(FallibleTArray<PRUint8>& aNameTable, PRUint32 aNameID, 
    1571                 :                         PRInt32 aPlatformID, nsTArray<nsString>& aNames)
    1572                 : {
    1573               0 :     return ReadNames(aNameTable, aNameID, LANG_ALL, aPlatformID, aNames);
    1574                 : }
    1575                 : 
    1576                 : nsresult
    1577               0 : gfxFontUtils::ReadCanonicalName(FallibleTArray<PRUint8>& aNameTable, PRUint32 aNameID, 
    1578                 :                                 nsString& aName)
    1579                 : {
    1580                 :     nsresult rv;
    1581                 :     
    1582               0 :     nsTArray<nsString> names;
    1583                 :     
    1584                 :     // first, look for the English name (this will succeed 99% of the time)
    1585               0 :     rv = ReadNames(aNameTable, aNameID, CANONICAL_LANG_ID, PLATFORM_ID, names);
    1586               0 :     NS_ENSURE_SUCCESS(rv, rv);
    1587                 :         
    1588                 :     // otherwise, grab names for all languages
    1589               0 :     if (names.Length() == 0) {
    1590               0 :         rv = ReadNames(aNameTable, aNameID, LANG_ALL, PLATFORM_ID, names);
    1591               0 :         NS_ENSURE_SUCCESS(rv, rv);
    1592                 :     }
    1593                 :     
    1594                 : #if defined(XP_MACOSX)
    1595                 :     // may be dealing with font that only has Microsoft name entries
    1596                 :     if (names.Length() == 0) {
    1597                 :         rv = ReadNames(aNameTable, aNameID, LANG_ID_MICROSOFT_EN_US, 
    1598                 :                        PLATFORM_ID_MICROSOFT, names);
    1599                 :         NS_ENSURE_SUCCESS(rv, rv);
    1600                 :         
    1601                 :         // getting really desperate now, take anything!
    1602                 :         if (names.Length() == 0) {
    1603                 :             rv = ReadNames(aNameTable, aNameID, LANG_ALL, 
    1604                 :                            PLATFORM_ID_MICROSOFT, names);
    1605                 :             NS_ENSURE_SUCCESS(rv, rv);
    1606                 :         }
    1607                 :     }
    1608                 : #endif
    1609                 : 
    1610                 :     // return the first name (99.9% of the time names will
    1611                 :     // contain a single English name)
    1612               0 :     if (names.Length()) {
    1613               0 :         aName.Assign(names[0]);
    1614               0 :         return NS_OK;
    1615                 :     }
    1616                 :         
    1617               0 :     return NS_ERROR_FAILURE;
    1618                 : }
    1619                 : 
    1620                 : // Charsets to use for decoding Mac platform font names.
    1621                 : // This table is sorted by {encoding, language}, with the wildcard "ANY" being
    1622                 : // greater than any defined values for each field; we use a binary search on both
    1623                 : // fields, and fall back to matching only encoding if necessary
    1624                 : 
    1625                 : // Some "redundant" entries for specific combinations are included such as
    1626                 : // encoding=roman, lang=english, in order that common entries will be found
    1627                 : // on the first search.
    1628                 : 
    1629                 : #define ANY 0xffff
    1630                 : const gfxFontUtils::MacFontNameCharsetMapping gfxFontUtils::gMacFontNameCharsets[] =
    1631                 : {
    1632                 :     { ENCODING_ID_MAC_ROMAN,        LANG_ID_MAC_ENGLISH,      "x-mac-roman"     },
    1633                 :     { ENCODING_ID_MAC_ROMAN,        LANG_ID_MAC_ICELANDIC,    "x-mac-icelandic" },
    1634                 :     { ENCODING_ID_MAC_ROMAN,        LANG_ID_MAC_TURKISH,      "x-mac-turkish"   },
    1635                 :     { ENCODING_ID_MAC_ROMAN,        LANG_ID_MAC_POLISH,       "x-mac-ce"        },
    1636                 :     { ENCODING_ID_MAC_ROMAN,        LANG_ID_MAC_ROMANIAN,     "x-mac-romanian"  },
    1637                 :     { ENCODING_ID_MAC_ROMAN,        LANG_ID_MAC_CZECH,        "x-mac-ce"        },
    1638                 :     { ENCODING_ID_MAC_ROMAN,        LANG_ID_MAC_SLOVAK,       "x-mac-ce"        },
    1639                 :     { ENCODING_ID_MAC_ROMAN,        ANY,                      "x-mac-roman"     },
    1640                 :     { ENCODING_ID_MAC_JAPANESE,     LANG_ID_MAC_JAPANESE,     "Shift_JIS"       },
    1641                 :     { ENCODING_ID_MAC_JAPANESE,     ANY,                      "Shift_JIS"       },
    1642                 :     { ENCODING_ID_MAC_TRAD_CHINESE, LANG_ID_MAC_TRAD_CHINESE, "Big5"            },
    1643                 :     { ENCODING_ID_MAC_TRAD_CHINESE, ANY,                      "Big5"            },
    1644                 :     { ENCODING_ID_MAC_KOREAN,       LANG_ID_MAC_KOREAN,       "EUC-KR"          },
    1645                 :     { ENCODING_ID_MAC_KOREAN,       ANY,                      "EUC-KR"          },
    1646                 :     { ENCODING_ID_MAC_ARABIC,       LANG_ID_MAC_ARABIC,       "x-mac-arabic"    },
    1647                 :     { ENCODING_ID_MAC_ARABIC,       LANG_ID_MAC_URDU,         "x-mac-farsi"     },
    1648                 :     { ENCODING_ID_MAC_ARABIC,       LANG_ID_MAC_FARSI,        "x-mac-farsi"     },
    1649                 :     { ENCODING_ID_MAC_ARABIC,       ANY,                      "x-mac-arabic"    },
    1650                 :     { ENCODING_ID_MAC_HEBREW,       LANG_ID_MAC_HEBREW,       "x-mac-hebrew"    },
    1651                 :     { ENCODING_ID_MAC_HEBREW,       ANY,                      "x-mac-hebrew"    },
    1652                 :     { ENCODING_ID_MAC_GREEK,        ANY,                      "x-mac-greek"     },
    1653                 :     { ENCODING_ID_MAC_CYRILLIC,     ANY,                      "x-mac-cyrillic"  },
    1654                 :     { ENCODING_ID_MAC_DEVANAGARI,   ANY,                      "x-mac-devanagari"},
    1655                 :     { ENCODING_ID_MAC_GURMUKHI,     ANY,                      "x-mac-gurmukhi"  },
    1656                 :     { ENCODING_ID_MAC_GUJARATI,     ANY,                      "x-mac-gujarati"  },
    1657                 :     { ENCODING_ID_MAC_SIMP_CHINESE, LANG_ID_MAC_SIMP_CHINESE, "GB2312"          },
    1658                 :     { ENCODING_ID_MAC_SIMP_CHINESE, ANY,                      "GB2312"          }
    1659                 : };
    1660                 : 
    1661                 : const char* gfxFontUtils::gISOFontNameCharsets[] = 
    1662                 : {
    1663                 :     /* 0 */ "us-ascii"   ,
    1664                 :     /* 1 */ nsnull       , /* spec says "ISO 10646" but does not specify encoding form! */
    1665                 :     /* 2 */ "ISO-8859-1"
    1666                 : };
    1667                 : 
    1668                 : const char* gfxFontUtils::gMSFontNameCharsets[] =
    1669                 : {
    1670                 :     /* [0] ENCODING_ID_MICROSOFT_SYMBOL */      ""          ,
    1671                 :     /* [1] ENCODING_ID_MICROSOFT_UNICODEBMP */  ""          ,
    1672                 :     /* [2] ENCODING_ID_MICROSOFT_SHIFTJIS */    "Shift_JIS" ,
    1673                 :     /* [3] ENCODING_ID_MICROSOFT_PRC */         nsnull      ,
    1674                 :     /* [4] ENCODING_ID_MICROSOFT_BIG5 */        "Big5"      ,
    1675                 :     /* [5] ENCODING_ID_MICROSOFT_WANSUNG */     nsnull      ,
    1676                 :     /* [6] ENCODING_ID_MICROSOFT_JOHAB */       "x-johab"   ,
    1677                 :     /* [7] reserved */                          nsnull      ,
    1678                 :     /* [8] reserved */                          nsnull      ,
    1679                 :     /* [9] reserved */                          nsnull      ,
    1680                 :     /*[10] ENCODING_ID_MICROSOFT_UNICODEFULL */ ""
    1681                 : };
    1682                 : 
    1683                 : #define ARRAY_SIZE(A) (sizeof(A) / sizeof(A[0]))
    1684                 : 
    1685                 : // Return the name of the charset we should use to decode a font name
    1686                 : // given the name table attributes.
    1687                 : // Special return values:
    1688                 : //    ""       charset is UTF16BE, no need for a converter
    1689                 : //    nsnull   unknown charset, do not attempt conversion
    1690                 : const char*
    1691               0 : gfxFontUtils::GetCharsetForFontName(PRUint16 aPlatform, PRUint16 aScript, PRUint16 aLanguage)
    1692                 : {
    1693               0 :     switch (aPlatform)
    1694                 :     {
    1695                 :     case PLATFORM_ID_UNICODE:
    1696               0 :         return "";
    1697                 : 
    1698                 :     case PLATFORM_ID_MAC:
    1699                 :         {
    1700               0 :             PRUint32 lo = 0, hi = ARRAY_SIZE(gMacFontNameCharsets);
    1701               0 :             MacFontNameCharsetMapping searchValue = { aScript, aLanguage, nsnull };
    1702               0 :             for (PRUint32 i = 0; i < 2; ++i) {
    1703                 :                 // binary search; if not found, set language to ANY and try again
    1704               0 :                 while (lo < hi) {
    1705               0 :                     PRUint32 mid = (lo + hi) / 2;
    1706               0 :                     const MacFontNameCharsetMapping& entry = gMacFontNameCharsets[mid];
    1707               0 :                     if (entry < searchValue) {
    1708               0 :                         lo = mid + 1;
    1709               0 :                         continue;
    1710                 :                     }
    1711               0 :                     if (searchValue < entry) {
    1712               0 :                         hi = mid;
    1713               0 :                         continue;
    1714                 :                     }
    1715                 :                     // found a match
    1716               0 :                     return entry.mCharsetName;
    1717                 :                 }
    1718                 : 
    1719                 :                 // no match, so reset high bound for search and re-try
    1720               0 :                 hi = ARRAY_SIZE(gMacFontNameCharsets);
    1721               0 :                 searchValue.mLanguage = ANY;
    1722                 :             }
    1723                 :         }
    1724               0 :         break;
    1725                 : 
    1726                 :     case PLATFORM_ID_ISO:
    1727               0 :         if (aScript < ARRAY_SIZE(gISOFontNameCharsets)) {
    1728               0 :             return gISOFontNameCharsets[aScript];
    1729                 :         }
    1730               0 :         break;
    1731                 : 
    1732                 :     case PLATFORM_ID_MICROSOFT:
    1733               0 :         if (aScript < ARRAY_SIZE(gMSFontNameCharsets)) {
    1734               0 :             return gMSFontNameCharsets[aScript];
    1735                 :         }
    1736               0 :         break;
    1737                 :     }
    1738                 : 
    1739               0 :     return nsnull;
    1740                 : }
    1741                 : 
    1742                 : // convert a raw name from the name table to an nsString, if possible;
    1743                 : // return value indicates whether conversion succeeded
    1744                 : bool
    1745               0 : gfxFontUtils::DecodeFontName(const PRUint8 *aNameData, PRInt32 aByteLen, 
    1746                 :                              PRUint32 aPlatformCode, PRUint32 aScriptCode,
    1747                 :                              PRUint32 aLangCode, nsAString& aName)
    1748                 : {
    1749               0 :     NS_ASSERTION(aByteLen > 0, "bad length for font name data");
    1750                 : 
    1751               0 :     const char *csName = GetCharsetForFontName(aPlatformCode, aScriptCode, aLangCode);
    1752                 : 
    1753               0 :     if (!csName) {
    1754                 :         // nsnull -> unknown charset
    1755                 : #ifdef DEBUG
    1756                 :         char warnBuf[128];
    1757               0 :         if (aByteLen > 64)
    1758               0 :             aByteLen = 64;
    1759                 :         sprintf(warnBuf, "skipping font name, unknown charset %d:%d:%d for <%.*s>",
    1760               0 :                 aPlatformCode, aScriptCode, aLangCode, aByteLen, aNameData);
    1761               0 :         NS_WARNING(warnBuf);
    1762                 : #endif
    1763               0 :         return false;
    1764                 :     }
    1765                 : 
    1766               0 :     if (csName[0] == 0) {
    1767                 :         // empty charset name: data is utf16be, no need to instantiate a converter
    1768               0 :         PRUint32 strLen = aByteLen / 2;
    1769                 : #ifdef IS_LITTLE_ENDIAN
    1770               0 :         aName.SetLength(strLen);
    1771                 :         CopySwapUTF16(reinterpret_cast<const PRUint16*>(aNameData),
    1772               0 :                       reinterpret_cast<PRUint16*>(aName.BeginWriting()), strLen);
    1773                 : #else
    1774                 :         aName.Assign(reinterpret_cast<const PRUnichar*>(aNameData), strLen);
    1775                 : #endif    
    1776               0 :         return true;
    1777                 :     }
    1778                 : 
    1779                 :     nsresult rv;
    1780                 :     nsCOMPtr<nsICharsetConverterManager> ccm =
    1781               0 :         do_GetService(NS_CHARSETCONVERTERMANAGER_CONTRACTID, &rv);
    1782               0 :     NS_ASSERTION(NS_SUCCEEDED(rv), "failed to get charset converter manager");
    1783               0 :     if (NS_FAILED(rv)) {
    1784               0 :         return false;
    1785                 :     }
    1786                 : 
    1787               0 :     nsCOMPtr<nsIUnicodeDecoder> decoder;
    1788               0 :     rv = ccm->GetUnicodeDecoderRawInternal(csName, getter_AddRefs(decoder));
    1789               0 :     if (NS_FAILED(rv)) {
    1790               0 :         NS_WARNING("failed to get the decoder for a font name string");
    1791               0 :         return false;
    1792                 :     }
    1793                 : 
    1794                 :     PRInt32 destLength;
    1795               0 :     rv = decoder->GetMaxLength(reinterpret_cast<const char*>(aNameData), aByteLen, &destLength);
    1796               0 :     if (NS_FAILED(rv)) {
    1797               0 :         NS_WARNING("decoder->GetMaxLength failed, invalid font name?");
    1798               0 :         return false;
    1799                 :     }
    1800                 : 
    1801                 :     // make space for the converted string
    1802               0 :     aName.SetLength(destLength);
    1803               0 :     rv = decoder->Convert(reinterpret_cast<const char*>(aNameData), &aByteLen,
    1804               0 :                           aName.BeginWriting(), &destLength);
    1805               0 :     if (NS_FAILED(rv)) {
    1806               0 :         NS_WARNING("decoder->Convert failed, invalid font name?");
    1807               0 :         return false;
    1808                 :     }
    1809               0 :     aName.Truncate(destLength); // set the actual length
    1810                 : 
    1811               0 :     return true;
    1812                 : }
    1813                 : 
    1814                 : nsresult
    1815               0 : gfxFontUtils::ReadNames(FallibleTArray<PRUint8>& aNameTable, PRUint32 aNameID, 
    1816                 :                         PRInt32 aLangID, PRInt32 aPlatformID,
    1817                 :                         nsTArray<nsString>& aNames)
    1818                 : {
    1819               0 :     PRUint32 nameTableLen = aNameTable.Length();
    1820               0 :     NS_ASSERTION(nameTableLen != 0, "null name table");
    1821                 : 
    1822               0 :     if (nameTableLen == 0)
    1823               0 :         return NS_ERROR_FAILURE;
    1824                 : 
    1825               0 :     PRUint8 *nameTable = aNameTable.Elements();
    1826                 : 
    1827                 :     // -- name table data
    1828               0 :     const NameHeader *nameHeader = reinterpret_cast<const NameHeader*>(nameTable);
    1829                 : 
    1830               0 :     PRUint32 nameCount = nameHeader->count;
    1831                 : 
    1832                 :     // -- sanity check the number of name records
    1833               0 :     if (PRUint64(nameCount) * sizeof(NameRecord) > nameTableLen) {
    1834               0 :         NS_WARNING("invalid font (name table data)");
    1835               0 :         return NS_ERROR_FAILURE;
    1836                 :     }
    1837                 :     
    1838                 :     // -- iterate through name records
    1839                 :     const NameRecord *nameRecord 
    1840               0 :         = reinterpret_cast<const NameRecord*>(nameTable + sizeof(NameHeader));
    1841               0 :     PRUint64 nameStringsBase = PRUint64(nameHeader->stringOffset);
    1842                 : 
    1843                 :     PRUint32 i;
    1844               0 :     for (i = 0; i < nameCount; i++, nameRecord++) {
    1845                 :         PRUint32 platformID;
    1846                 :         
    1847                 :         // skip over unwanted nameID's
    1848               0 :         if (PRUint32(nameRecord->nameID) != aNameID)
    1849               0 :             continue;
    1850                 : 
    1851                 :         // skip over unwanted platform data
    1852               0 :         platformID = nameRecord->platformID;
    1853               0 :         if (aPlatformID != PLATFORM_ALL 
    1854               0 :             && PRUint32(nameRecord->platformID) != PLATFORM_ID)
    1855               0 :             continue;
    1856                 :             
    1857                 :         // skip over unwanted languages
    1858               0 :         if (aLangID != LANG_ALL 
    1859               0 :               && PRUint32(nameRecord->languageID) != PRUint32(aLangID))
    1860               0 :             continue;
    1861                 :         
    1862                 :         // add name to names array
    1863                 :         
    1864                 :         // -- calculate string location
    1865               0 :         PRUint32 namelen = nameRecord->length;
    1866               0 :         PRUint32 nameoff = nameRecord->offset;  // offset from base of string storage
    1867                 : 
    1868               0 :         if (nameStringsBase + PRUint64(nameoff) + PRUint64(namelen) 
    1869                 :                 > nameTableLen) {
    1870               0 :             NS_WARNING("invalid font (name table strings)");
    1871               0 :             return NS_ERROR_FAILURE;
    1872                 :         }
    1873                 :         
    1874                 :         // -- decode if necessary and make nsString
    1875               0 :         nsAutoString name;
    1876                 :         nsresult rv;
    1877                 :         
    1878               0 :         rv = DecodeFontName(nameTable + nameStringsBase + nameoff, namelen, 
    1879                 :                             platformID, PRUint32(nameRecord->encodingID),
    1880               0 :                             PRUint32(nameRecord->languageID), name);
    1881                 :         
    1882               0 :         if (NS_FAILED(rv))
    1883               0 :             continue;
    1884                 :             
    1885                 :         PRUint32 k, numNames;
    1886               0 :         bool foundName = false;
    1887                 :         
    1888               0 :         numNames = aNames.Length();
    1889               0 :         for (k = 0; k < numNames; k++) {
    1890               0 :             if (name.Equals(aNames[k])) {
    1891               0 :                 foundName = true;
    1892               0 :                 break;
    1893                 :             }    
    1894                 :         }
    1895                 :         
    1896               0 :         if (!foundName)
    1897               0 :             aNames.AppendElement(name);                          
    1898                 : 
    1899                 :     }
    1900                 : 
    1901               0 :     return NS_OK;
    1902                 : }
    1903                 : 
    1904                 : #ifdef XP_WIN
    1905                 : 
    1906                 : // Embedded OpenType (EOT) handling
    1907                 : // needed for dealing with downloadable fonts on Windows
    1908                 : //
    1909                 : // EOT version 0x00020001
    1910                 : // based on http://www.w3.org/Submission/2008/SUBM-EOT-20080305/
    1911                 : //
    1912                 : // EOT header consists of a fixed-size portion containing general font
    1913                 : // info, followed by a variable-sized portion containing name data,
    1914                 : // followed by the actual TT/OT font data (non-byte values are always
    1915                 : // stored in big-endian format)
    1916                 : //
    1917                 : // EOT header is stored in *little* endian order!!
    1918                 : 
    1919                 : #pragma pack(1)
    1920                 : 
    1921                 : struct EOTFixedHeader {
    1922                 : 
    1923                 :     PRUint32      eotSize;            // Total structure length in PRUint8s (including string and font data)
    1924                 :     PRUint32      fontDataSize;       // Length of the OpenType font (FontData) in PRUint8s
    1925                 :     PRUint32      version;            // Version number of this format - 0x00010000
    1926                 :     PRUint32      flags;              // Processing Flags
    1927                 :     PRUint8       panose[10];         // The PANOSE value for this font - See http://www.microsoft.com/typography/otspec/os2.htm#pan
    1928                 :     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
    1929                 :     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
    1930                 :     PRUint32      weight;             // The weight value for this font - See http://www.microsoft.com/typography/otspec/os2.htm#wtc
    1931                 :     PRUint16      fsType;             // Type flags that provide information about embedding permissions - See http://www.microsoft.com/typography/otspec/os2.htm#fst
    1932                 :     PRUint16      magicNumber;        // Magic number for EOT file - 0x504C. Used to check for data corruption.
    1933                 :     PRUint32      unicodeRange1;      // OS/2.UnicodeRange1 (bits 0-31) - See http://www.microsoft.com/typography/otspec/os2.htm#ur
    1934                 :     PRUint32      unicodeRange2;      // OS/2.UnicodeRange2 (bits 32-63) - See http://www.microsoft.com/typography/otspec/os2.htm#ur
    1935                 :     PRUint32      unicodeRange3;      // OS/2.UnicodeRange3 (bits 64-95) - See http://www.microsoft.com/typography/otspec/os2.htm#ur
    1936                 :     PRUint32      unicodeRange4;      // OS/2.UnicodeRange4 (bits 96-127) - See http://www.microsoft.com/typography/otspec/os2.htm#ur
    1937                 :     PRUint32      codePageRange1;     // CodePageRange1 (bits 0-31) - See http://www.microsoft.com/typography/otspec/os2.htm#cpr
    1938                 :     PRUint32      codePageRange2;     // CodePageRange2 (bits 32-63) - See http://www.microsoft.com/typography/otspec/os2.htm#cpr
    1939                 :     PRUint32      checkSumAdjustment; // head.CheckSumAdjustment - See http://www.microsoft.com/typography/otspec/head.htm
    1940                 :     PRUint32      reserved[4];        // Reserved - must be 0
    1941                 :     PRUint16      padding1;           // Padding to maintain long alignment. Padding value must always be set to 0x0000.
    1942                 : 
    1943                 :     enum {
    1944                 :         EOT_VERSION = 0x00020001,
    1945                 :         EOT_MAGIC_NUMBER = 0x504c,
    1946                 :         EOT_DEFAULT_CHARSET = 0x01,
    1947                 :         EOT_EMBED_PRINT_PREVIEW = 0x0004,
    1948                 :         EOT_FAMILY_NAME_INDEX = 0,    // order of names in variable portion of EOT header
    1949                 :         EOT_STYLE_NAME_INDEX = 1,
    1950                 :         EOT_VERSION_NAME_INDEX = 2,
    1951                 :         EOT_FULL_NAME_INDEX = 3,
    1952                 :         EOT_NUM_NAMES = 4
    1953                 :     };
    1954                 : 
    1955                 : };
    1956                 : 
    1957                 : #pragma pack()
    1958                 : 
    1959                 : // EOT headers are only used on Windows
    1960                 : 
    1961                 : // EOT variable-sized header (version 0x00020001 - contains 4 name
    1962                 : // fields, each with the structure):
    1963                 : //
    1964                 : //   // number of bytes in the name array
    1965                 : //   PRUint16 size;
    1966                 : //   // array of UTF-16 chars, total length = <size> bytes
    1967                 : //   // note: english version of name record string
    1968                 : //   PRUint8  name[size]; 
    1969                 : //
    1970                 : // This structure is used for the following names, each separated by two
    1971                 : // bytes of padding (always 0 with no padding after the rootString):
    1972                 : //
    1973                 : //   familyName  - based on name ID = 1
    1974                 : //   styleName   - based on name ID = 2
    1975                 : //   versionName - based on name ID = 5
    1976                 : //   fullName    - based on name ID = 4
    1977                 : //   rootString  - used to restrict font usage to a specific domain
    1978                 : //
    1979                 : 
    1980                 : #if DEBUG
    1981                 : static void 
    1982                 : DumpEOTHeader(PRUint8 *aHeader, PRUint32 aHeaderLen)
    1983                 : {
    1984                 :     PRUint32 offset = 0;
    1985                 :     PRUint8 *ch = aHeader;
    1986                 : 
    1987                 :     printf("\n\nlen == %d\n\n", aHeaderLen);
    1988                 :     while (offset < aHeaderLen) {
    1989                 :         printf("%7.7x    ", offset);
    1990                 :         int i;
    1991                 :         for (i = 0; i < 16; i++) {
    1992                 :             printf("%2.2x  ", *ch++);
    1993                 :         }
    1994                 :         printf("\n");
    1995                 :         offset += 16;
    1996                 :     }
    1997                 : }
    1998                 : #endif
    1999                 : 
    2000                 : nsresult
    2001                 : gfxFontUtils::MakeEOTHeader(const PRUint8 *aFontData, PRUint32 aFontDataLength,
    2002                 :                             FallibleTArray<PRUint8> *aHeader,
    2003                 :                             FontDataOverlay *aOverlay)
    2004                 : {
    2005                 :     NS_ASSERTION(aFontData && aFontDataLength != 0, "null font data");
    2006                 :     NS_ASSERTION(aHeader, "null header");
    2007                 :     NS_ASSERTION(aHeader->Length() == 0, "non-empty header passed in");
    2008                 :     NS_ASSERTION(aOverlay, "null font overlay struct passed in");
    2009                 : 
    2010                 :     aOverlay->overlaySrc = 0;
    2011                 :     
    2012                 :     if (!aHeader->AppendElements(sizeof(EOTFixedHeader)))
    2013                 :         return NS_ERROR_OUT_OF_MEMORY;
    2014                 : 
    2015                 :     EOTFixedHeader *eotHeader = reinterpret_cast<EOTFixedHeader*>(aHeader->Elements());
    2016                 :     memset(eotHeader, 0, sizeof(EOTFixedHeader));
    2017                 : 
    2018                 :     PRUint32 fontDataSize = aFontDataLength;
    2019                 : 
    2020                 :     // set up header fields
    2021                 :     eotHeader->fontDataSize = fontDataSize;
    2022                 :     eotHeader->version = EOTFixedHeader::EOT_VERSION;
    2023                 :     eotHeader->flags = 0;  // don't specify any special processing
    2024                 :     eotHeader->charset = EOTFixedHeader::EOT_DEFAULT_CHARSET;
    2025                 :     eotHeader->fsType = EOTFixedHeader::EOT_EMBED_PRINT_PREVIEW;
    2026                 :     eotHeader->magicNumber = EOTFixedHeader::EOT_MAGIC_NUMBER;
    2027                 : 
    2028                 :     // read in the sfnt header
    2029                 :     if (sizeof(SFNTHeader) > aFontDataLength)
    2030                 :         return NS_ERROR_FAILURE;
    2031                 :     
    2032                 :     const SFNTHeader *sfntHeader = reinterpret_cast<const SFNTHeader*>(aFontData);
    2033                 :     if (!IsValidSFNTVersion(sfntHeader->sfntVersion))
    2034                 :         return NS_ERROR_FAILURE;
    2035                 : 
    2036                 :     // iterate through the table headers to find the head, name and OS/2 tables
    2037                 :     bool foundHead = false, foundOS2 = false, foundName = false, foundGlyphs = false;
    2038                 :     PRUint32 headOffset, headLen, nameOffset, nameLen, os2Offset, os2Len;
    2039                 :     PRUint32 i, numTables;
    2040                 : 
    2041                 :     numTables = sfntHeader->numTables;
    2042                 :     if (sizeof(SFNTHeader) + sizeof(TableDirEntry) * numTables > aFontDataLength)
    2043                 :         return NS_ERROR_FAILURE;
    2044                 :     
    2045                 :     PRUint64 dataLength(aFontDataLength);
    2046                 :     
    2047                 :     // table directory entries begin immediately following SFNT header
    2048                 :     const TableDirEntry *dirEntry = reinterpret_cast<const TableDirEntry*>(aFontData + sizeof(SFNTHeader));
    2049                 :     
    2050                 :     for (i = 0; i < numTables; i++, dirEntry++) {
    2051                 :     
    2052                 :         // sanity check on offset, length values
    2053                 :         if (PRUint64(dirEntry->offset) + PRUint64(dirEntry->length) > dataLength)
    2054                 :             return NS_ERROR_FAILURE;
    2055                 : 
    2056                 :         switch (dirEntry->tag) {
    2057                 : 
    2058                 :         case TRUETYPE_TAG('h','e','a','d'):
    2059                 :             foundHead = true;
    2060                 :             headOffset = dirEntry->offset;
    2061                 :             headLen = dirEntry->length;
    2062                 :             if (headLen < sizeof(HeadTable))
    2063                 :                 return NS_ERROR_FAILURE;
    2064                 :             break;
    2065                 : 
    2066                 :         case TRUETYPE_TAG('n','a','m','e'):
    2067                 :             foundName = true;
    2068                 :             nameOffset = dirEntry->offset;
    2069                 :             nameLen = dirEntry->length;
    2070                 :             break;
    2071                 : 
    2072                 :         case TRUETYPE_TAG('O','S','/','2'):
    2073                 :             foundOS2 = true;
    2074                 :             os2Offset = dirEntry->offset;
    2075                 :             os2Len = dirEntry->length;
    2076                 :             break;
    2077                 : 
    2078                 :         case TRUETYPE_TAG('g','l','y','f'):  // TrueType-style quadratic glyph table
    2079                 :             foundGlyphs = true;
    2080                 :             break;
    2081                 : 
    2082                 :         case TRUETYPE_TAG('C','F','F',' '):  // PS-style cubic glyph table
    2083                 :             foundGlyphs = true;
    2084                 :             break;
    2085                 : 
    2086                 :         default:
    2087                 :             break;
    2088                 :         }
    2089                 : 
    2090                 :         if (foundHead && foundName && foundOS2 && foundGlyphs)
    2091                 :             break;
    2092                 :     }
    2093                 : 
    2094                 :     // require these three tables on Windows
    2095                 :     if (!foundHead || !foundName || !foundOS2)
    2096                 :         return NS_ERROR_FAILURE;
    2097                 : 
    2098                 :     // at this point, all table offset/length values are within bounds
    2099                 :     
    2100                 :     // read in the data from those tables
    2101                 : 
    2102                 :     // -- head table data
    2103                 :     const HeadTable  *headData = reinterpret_cast<const HeadTable*>(aFontData + headOffset);
    2104                 : 
    2105                 :     if (headData->tableVersionNumber != HeadTable::HEAD_VERSION ||
    2106                 :         headData->magicNumber != HeadTable::HEAD_MAGIC_NUMBER) {
    2107                 :         return NS_ERROR_FAILURE;
    2108                 :     }
    2109                 : 
    2110                 :     eotHeader->checkSumAdjustment = headData->checkSumAdjustment;
    2111                 : 
    2112                 :     // -- name table data
    2113                 : 
    2114                 :     // -- first, read name table header
    2115                 :     const NameHeader *nameHeader = reinterpret_cast<const NameHeader*>(aFontData + nameOffset);
    2116                 :     PRUint32 nameStringsBase = PRUint32(nameHeader->stringOffset);
    2117                 : 
    2118                 :     PRUint32 nameCount = nameHeader->count;
    2119                 : 
    2120                 :     // -- sanity check the number of name records
    2121                 :     if (PRUint64(nameCount) * sizeof(NameRecord) + PRUint64(nameOffset) > dataLength)
    2122                 :         return NS_ERROR_FAILURE;
    2123                 : 
    2124                 :     // bug 496573 -- dummy names in case the font didn't contain English names
    2125                 :     const nsString dummyNames[EOTFixedHeader::EOT_NUM_NAMES] = {
    2126                 :         NS_LITERAL_STRING("Unknown"),
    2127                 :         NS_LITERAL_STRING("Regular"),
    2128                 :         EmptyString(),
    2129                 :         dummyNames[EOTFixedHeader::EOT_FAMILY_NAME_INDEX]
    2130                 :     };
    2131                 : 
    2132                 :     // -- iterate through name records, look for specific name ids with
    2133                 :     //    matching platform/encoding/etc. and store offset/lengths
    2134                 :     NameRecordData names[EOTFixedHeader::EOT_NUM_NAMES] = {0};
    2135                 :     const NameRecord *nameRecord = reinterpret_cast<const NameRecord*>(aFontData + nameOffset + sizeof(NameHeader));
    2136                 :     PRUint32 needNames = (1 << EOTFixedHeader::EOT_FAMILY_NAME_INDEX) | 
    2137                 :                          (1 << EOTFixedHeader::EOT_STYLE_NAME_INDEX) | 
    2138                 :                          (1 << EOTFixedHeader::EOT_FULL_NAME_INDEX) | 
    2139                 :                          (1 << EOTFixedHeader::EOT_VERSION_NAME_INDEX);
    2140                 : 
    2141                 :     for (i = 0; i < nameCount; i++, nameRecord++) {
    2142                 : 
    2143                 :         // looking for Microsoft English US name strings, skip others
    2144                 :         if (PRUint32(nameRecord->platformID) != PLATFORM_ID_MICROSOFT || 
    2145                 :                 PRUint32(nameRecord->encodingID) != ENCODING_ID_MICROSOFT_UNICODEBMP || 
    2146                 :                 PRUint32(nameRecord->languageID) != LANG_ID_MICROSOFT_EN_US)
    2147                 :             continue;
    2148                 : 
    2149                 :         PRUint32 index;
    2150                 :         switch ((PRUint32)nameRecord->nameID) {
    2151                 : 
    2152                 :         case NAME_ID_FAMILY:
    2153                 :             index = EOTFixedHeader::EOT_FAMILY_NAME_INDEX;
    2154                 :             break;
    2155                 : 
    2156                 :         case NAME_ID_STYLE:
    2157                 :             index = EOTFixedHeader::EOT_STYLE_NAME_INDEX;
    2158                 :             break;
    2159                 : 
    2160                 :         case NAME_ID_FULL:
    2161                 :             index = EOTFixedHeader::EOT_FULL_NAME_INDEX;
    2162                 :             break;
    2163                 : 
    2164                 :         case NAME_ID_VERSION:
    2165                 :             index = EOTFixedHeader::EOT_VERSION_NAME_INDEX;
    2166                 :             break;
    2167                 : 
    2168                 :         default:
    2169                 :             continue;
    2170                 :         }
    2171                 : 
    2172                 :         names[index].offset = nameRecord->offset;
    2173                 :         names[index].length = nameRecord->length;
    2174                 :         needNames &= ~(1 << index);
    2175                 : 
    2176                 :         if (needNames == 0)
    2177                 :             break;
    2178                 :     }
    2179                 : 
    2180                 :     // -- expand buffer if needed to include variable-length portion
    2181                 :     PRUint32 eotVariableLength = 0;
    2182                 :     for (i = 0; i < EOTFixedHeader::EOT_NUM_NAMES; i++) {
    2183                 :         if (!(needNames & (1 << i))) {
    2184                 :             eotVariableLength += names[i].length & (~1);
    2185                 :         } else {
    2186                 :             eotVariableLength += dummyNames[i].Length() * sizeof(PRUnichar);
    2187                 :         }
    2188                 :     }
    2189                 :     eotVariableLength += EOTFixedHeader::EOT_NUM_NAMES * (2 /* size */ 
    2190                 :                                                           + 2 /* padding */) +
    2191                 :                          2 /* null root string size */;
    2192                 : 
    2193                 :     if (!aHeader->AppendElements(eotVariableLength))
    2194                 :         return NS_ERROR_OUT_OF_MEMORY;
    2195                 : 
    2196                 :     // append the string data to the end of the EOT header
    2197                 :     PRUint8 *eotEnd = aHeader->Elements() + sizeof(EOTFixedHeader);
    2198                 :     PRUint32 strOffset, strLen;
    2199                 : 
    2200                 :     for (i = 0; i < EOTFixedHeader::EOT_NUM_NAMES; i++) {
    2201                 :         if (!(needNames & (1 << i))) {
    2202                 :             PRUint32 namelen = names[i].length;
    2203                 :             PRUint32 nameoff = names[i].offset;  // offset from base of string storage
    2204                 : 
    2205                 :             // sanity check the name string location
    2206                 :             if (PRUint64(nameOffset) + PRUint64(nameStringsBase) +
    2207                 :                 PRUint64(nameoff) + PRUint64(namelen) > dataLength) {
    2208                 :                 return NS_ERROR_FAILURE;
    2209                 :             }
    2210                 : 
    2211                 :             strOffset = nameOffset + nameStringsBase + nameoff;
    2212                 : 
    2213                 :             // output 2-byte str size
    2214                 :             strLen = namelen & (~1);  // UTF-16 string len must be even
    2215                 :             *((PRUint16*) eotEnd) = PRUint16(strLen);
    2216                 :             eotEnd += 2;
    2217                 : 
    2218                 :             // length is number of UTF-16 chars, not bytes
    2219                 :             CopySwapUTF16(reinterpret_cast<const PRUint16*>(aFontData + strOffset),
    2220                 :                           reinterpret_cast<PRUint16*>(eotEnd),
    2221                 :                           (strLen >> 1));
    2222                 :         } else {
    2223                 :             // bug 496573 -- English names are not present.
    2224                 :             // supply an artificial one.
    2225                 :             strLen = dummyNames[i].Length() * sizeof(PRUnichar);
    2226                 :             *((PRUint16*) eotEnd) = PRUint16(strLen);
    2227                 :             eotEnd += 2;
    2228                 : 
    2229                 :             memcpy(eotEnd, dummyNames[i].BeginReading(), strLen);
    2230                 :         }
    2231                 :         eotEnd += strLen;
    2232                 : 
    2233                 :         // add 2-byte zero padding to the end of each string
    2234                 :         *eotEnd++ = 0;
    2235                 :         *eotEnd++ = 0;
    2236                 : 
    2237                 :         // Note: Microsoft's WEFT tool produces name strings which
    2238                 :         // include an extra null at the end of each string, in addition
    2239                 :         // to the 2-byte zero padding that separates the string fields. 
    2240                 :         // Don't think this is important to imitate...
    2241                 :     }
    2242                 : 
    2243                 :     // append null root string size
    2244                 :     *eotEnd++ = 0;
    2245                 :     *eotEnd++ = 0;
    2246                 : 
    2247                 :     NS_ASSERTION(eotEnd == aHeader->Elements() + aHeader->Length(), 
    2248                 :                  "header length calculation incorrect");
    2249                 :                  
    2250                 :     // bug 496573 -- fonts with a fullname that does not begin with the 
    2251                 :     // family name cause the EOT font loading API to hiccup
    2252                 :     PRUint32 famOff = names[EOTFixedHeader::EOT_FAMILY_NAME_INDEX].offset;
    2253                 :     PRUint32 famLen = names[EOTFixedHeader::EOT_FAMILY_NAME_INDEX].length;
    2254                 :     PRUint32 fullOff = names[EOTFixedHeader::EOT_FULL_NAME_INDEX].offset;
    2255                 :     PRUint32 fullLen = names[EOTFixedHeader::EOT_FULL_NAME_INDEX].length;
    2256                 :     
    2257                 :     const PRUint8 *nameStrings = aFontData + nameOffset + nameStringsBase;
    2258                 : 
    2259                 :     // assure that the start of the fullname matches the family name
    2260                 :     if (famLen <= fullLen 
    2261                 :         && memcmp(nameStrings + famOff, nameStrings + fullOff, famLen)) {
    2262                 :         aOverlay->overlaySrc = nameOffset + nameStringsBase + famOff;
    2263                 :         aOverlay->overlaySrcLen = famLen;
    2264                 :         aOverlay->overlayDest = nameOffset + nameStringsBase + fullOff;
    2265                 :     }
    2266                 : 
    2267                 :     // -- OS/2 table data
    2268                 :     const OS2Table *os2Data = reinterpret_cast<const OS2Table*>(aFontData + os2Offset);
    2269                 : 
    2270                 :     memcpy(eotHeader->panose, os2Data->panose, sizeof(eotHeader->panose));
    2271                 : 
    2272                 :     eotHeader->italic = (PRUint16) os2Data->fsSelection & 0x01;
    2273                 :     eotHeader->weight = os2Data->usWeightClass;
    2274                 :     eotHeader->unicodeRange1 = os2Data->unicodeRange1;
    2275                 :     eotHeader->unicodeRange2 = os2Data->unicodeRange2;
    2276                 :     eotHeader->unicodeRange3 = os2Data->unicodeRange3;
    2277                 :     eotHeader->unicodeRange4 = os2Data->unicodeRange4;
    2278                 :     eotHeader->codePageRange1 = os2Data->codePageRange1;
    2279                 :     eotHeader->codePageRange2 = os2Data->codePageRange2;
    2280                 : 
    2281                 :     eotHeader->eotSize = aHeader->Length() + fontDataSize;
    2282                 : 
    2283                 :     // DumpEOTHeader(aHeader->Elements(), aHeader->Length());
    2284                 : 
    2285                 :     return NS_OK;
    2286                 : }
    2287                 : 
    2288                 : /* static */
    2289                 : bool
    2290                 : gfxFontUtils::IsCffFont(const PRUint8* aFontData, bool& hasVertical)
    2291                 : {
    2292                 :     // this is only called after aFontData has passed basic validation,
    2293                 :     // so we know there is enough data present to allow us to read the version!
    2294                 :     const SFNTHeader *sfntHeader = reinterpret_cast<const SFNTHeader*>(aFontData);
    2295                 : 
    2296                 :     PRUint32 i;
    2297                 :     PRUint32 numTables = sfntHeader->numTables;
    2298                 :     const TableDirEntry *dirEntry = 
    2299                 :         reinterpret_cast<const TableDirEntry*>(aFontData + sizeof(SFNTHeader));
    2300                 :     hasVertical = false;
    2301                 :     for (i = 0; i < numTables; i++, dirEntry++) {
    2302                 :         if (dirEntry->tag == TRUETYPE_TAG('v','h','e','a')) {
    2303                 :             hasVertical = true;
    2304                 :             break;
    2305                 :         }
    2306                 :     }
    2307                 : 
    2308                 :     return (sfntHeader->sfntVersion == TRUETYPE_TAG('O','T','T','O'));
    2309                 : }
    2310                 : 
    2311                 : #endif

Generated by: LCOV version 1.7