зеркало из https://github.com/mozilla/pjs.git
Bug 396137. Use Windows cmap font matching in place of ATSUI font matching. r+sr=pavlov
This commit is contained in:
Родитель
f0c5fb13dc
Коммит
fff2edbec6
|
@ -17,6 +17,7 @@ EXPORTS = gfxASurface.h \
|
|||
gfxColor.h \
|
||||
gfxContext.h \
|
||||
gfxFont.h \
|
||||
gfxFontUtils.h \
|
||||
gfxImageSurface.h \
|
||||
gfxMatrix.h \
|
||||
gfxPath.h \
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
* Contributor(s):
|
||||
* Vladimir Vukicevic <vladimir@pobox.com>
|
||||
* Masayuki Nakano <masayuki@d-toybox.com>
|
||||
* John Daggett <jdaggett@mozilla.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
|
@ -42,10 +43,12 @@
|
|||
#include "cairo.h"
|
||||
#include "gfxTypes.h"
|
||||
#include "gfxFont.h"
|
||||
#include "gfxFontUtils.h"
|
||||
|
||||
#include <Carbon/Carbon.h>
|
||||
|
||||
class gfxAtsuiFontGroup;
|
||||
class FontEntry;
|
||||
|
||||
class gfxAtsuiFont : public gfxFont {
|
||||
public:
|
||||
|
@ -75,12 +78,16 @@ public:
|
|||
virtual void SetupGlyphExtents(gfxContext *aContext, PRUint32 aGlyphID,
|
||||
PRBool aNeedTight, gfxGlyphExtents *aExtents);
|
||||
|
||||
PRBool TestCharacterMap(PRUint32 aCh);
|
||||
|
||||
protected:
|
||||
const gfxFontStyle *mFontStyle;
|
||||
|
||||
ATSUFontID mATSUFontID;
|
||||
ATSUStyle mATSUStyle;
|
||||
|
||||
|
||||
nsRefPtr<FontEntry> mFontEntry;
|
||||
|
||||
PRBool mHasMirroring;
|
||||
PRBool mHasMirroringLookedUp;
|
||||
|
||||
|
@ -103,7 +110,7 @@ class THEBES_API gfxAtsuiFontGroup : public gfxFontGroup {
|
|||
public:
|
||||
gfxAtsuiFontGroup(const nsAString& families,
|
||||
const gfxFontStyle *aStyle);
|
||||
virtual ~gfxAtsuiFontGroup();
|
||||
virtual ~gfxAtsuiFontGroup() {};
|
||||
|
||||
virtual gfxFontGroup *Copy(const gfxFontStyle *aStyle);
|
||||
|
||||
|
@ -120,15 +127,25 @@ public:
|
|||
void MakeTextRunInternal(const PRUnichar *aString, PRUint32 aLength,
|
||||
PRBool aWrapped, gfxTextRun *aTextRun);
|
||||
|
||||
ATSUFontFallbacks *GetATSUFontFallbacksPtr() { return &mFallbacks; }
|
||||
|
||||
gfxAtsuiFont* GetFontAt(PRInt32 i) {
|
||||
return static_cast<gfxAtsuiFont*>(static_cast<gfxFont*>(mFonts[i]));
|
||||
gfxAtsuiFont* GetFontAt(PRInt32 aFontIndex) {
|
||||
return static_cast<gfxAtsuiFont*>(static_cast<gfxFont*>(mFonts[aFontIndex]));
|
||||
}
|
||||
|
||||
gfxAtsuiFont* FindFontFor(ATSUFontID fid);
|
||||
|
||||
PRBool HasFont(ATSUFontID fid);
|
||||
|
||||
inline gfxAtsuiFont* WhichFontSupportsChar(nsTArray< nsRefPtr<gfxFont> >& aFontList, PRUint32 aCh) {
|
||||
PRUint32 len = aFontList.Length();
|
||||
for (PRUint32 i = 0; i < len; i++) {
|
||||
gfxAtsuiFont* font = static_cast<gfxAtsuiFont*>(aFontList.ElementAt(i).get());
|
||||
if (font->TestCharacterMap(aCh))
|
||||
return font;
|
||||
}
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
already_AddRefed<gfxAtsuiFont> FindFontForChar(PRUint32 aCh, PRUint32 aPrevCh, PRUint32 aNextCh, gfxAtsuiFont* aPrevMatchedFont);
|
||||
|
||||
protected:
|
||||
static PRBool FindATSUFont(const nsAString& aName,
|
||||
|
@ -141,6 +158,5 @@ protected:
|
|||
PRBool InitTextRun(gfxTextRun *aRun, const PRUnichar *aString, PRUint32 aLength,
|
||||
PRBool aWrapped, PRUint32 aSegmentStart, PRUint32 aSegmentLength);
|
||||
|
||||
ATSUFontFallbacks mFallbacks;
|
||||
};
|
||||
#endif /* GFX_ATSUIFONTS_H */
|
||||
|
|
|
@ -0,0 +1,200 @@
|
|||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Mozilla Foundation code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2005
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Stuart Parmenter <stuart@mozilla.com>
|
||||
* John Daggett <jdaggett@mozilla.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef GFX_FONT_UTILS_H
|
||||
#define GFX_FONT_UTILS_H
|
||||
|
||||
#include "gfxTypes.h"
|
||||
|
||||
#include "prtypes.h"
|
||||
#include "gfxFont.h"
|
||||
#include "prcpucfg.h"
|
||||
|
||||
#include "nsDataHashtable.h"
|
||||
|
||||
/* Bug 341128 - w32api defines min/max which causes problems with <bitset> */
|
||||
#ifdef __MINGW32__
|
||||
#undef min
|
||||
#undef max
|
||||
#endif
|
||||
|
||||
#include <bitset>
|
||||
|
||||
// code from gfxWindowsFonts.h
|
||||
|
||||
class gfxSparseBitSet {
|
||||
private:
|
||||
enum { BLOCK_SIZE = 32 };
|
||||
enum { BLOCK_SIZE_BITS = BLOCK_SIZE * 8 };
|
||||
|
||||
struct Block {
|
||||
Block(unsigned char memsetValue = 0) { memset(mBits, memsetValue, BLOCK_SIZE); }
|
||||
PRUint8 mBits[BLOCK_SIZE];
|
||||
};
|
||||
|
||||
public:
|
||||
PRBool test(PRUint32 aIndex) {
|
||||
PRUint32 blockIndex = aIndex/BLOCK_SIZE_BITS;
|
||||
if (blockIndex >= mBlocks.Length())
|
||||
return PR_FALSE;
|
||||
Block *block = mBlocks[blockIndex];
|
||||
if (!block)
|
||||
return PR_FALSE;
|
||||
return ((block->mBits[(aIndex/8) & (BLOCK_SIZE - 1)]) & (1 << (aIndex & 0x7))) != 0;
|
||||
}
|
||||
|
||||
void set(PRUint32 aIndex) {
|
||||
PRUint32 blockIndex = aIndex/BLOCK_SIZE_BITS;
|
||||
if (blockIndex >= mBlocks.Length()) {
|
||||
nsAutoPtr<Block> *blocks = mBlocks.AppendElements(blockIndex + 1 - mBlocks.Length());
|
||||
if (NS_UNLIKELY(!blocks)) // OOM
|
||||
return;
|
||||
}
|
||||
Block *block = mBlocks[blockIndex];
|
||||
if (!block) {
|
||||
block = new Block;
|
||||
if (NS_UNLIKELY(!block)) // OOM
|
||||
return;
|
||||
mBlocks[blockIndex] = block;
|
||||
}
|
||||
block->mBits[(aIndex/8) & (BLOCK_SIZE - 1)] |= 1 << (aIndex & 0x7);
|
||||
}
|
||||
|
||||
void SetRange(PRUint32 aStart, PRUint32 aEnd) {
|
||||
const PRUint32 startIndex = aStart/BLOCK_SIZE_BITS;
|
||||
const PRUint32 endIndex = aEnd/BLOCK_SIZE_BITS;
|
||||
|
||||
if (endIndex >= mBlocks.Length()) {
|
||||
PRUint32 numNewBlocks = endIndex + 1 - mBlocks.Length();
|
||||
nsAutoPtr<Block> *blocks = mBlocks.AppendElements(numNewBlocks);
|
||||
if (NS_UNLIKELY(!blocks)) // OOM
|
||||
return;
|
||||
}
|
||||
|
||||
for (PRUint32 i = startIndex; i <= endIndex; ++i) {
|
||||
const PRUint32 blockFirstBit = i * BLOCK_SIZE_BITS;
|
||||
const PRUint32 blockLastBit = blockFirstBit + BLOCK_SIZE_BITS - 1;
|
||||
|
||||
Block *block = mBlocks[i];
|
||||
if (!block) {
|
||||
PRBool fullBlock = PR_FALSE;
|
||||
if (aStart <= blockFirstBit && aEnd >= blockLastBit)
|
||||
fullBlock = PR_TRUE;
|
||||
|
||||
block = new Block(fullBlock ? 0xFF : 0);
|
||||
|
||||
if (NS_UNLIKELY(!block)) // OOM
|
||||
return;
|
||||
mBlocks[i] = block;
|
||||
|
||||
if (fullBlock)
|
||||
continue;
|
||||
}
|
||||
|
||||
const PRUint32 start = aStart > blockFirstBit ? aStart - blockFirstBit : 0;
|
||||
const PRUint32 end = PR_MIN(aEnd - blockFirstBit, BLOCK_SIZE_BITS - 1);
|
||||
|
||||
for (PRUint32 bit = start; bit <= end; ++bit) {
|
||||
block->mBits[bit/8] |= 1 << (bit & 0x7);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PRUint32 GetSize() {
|
||||
PRUint32 size = 0;
|
||||
for (PRUint32 i = 0; i < mBlocks.Length(); i++)
|
||||
if (mBlocks[i])
|
||||
size += sizeof(Block);
|
||||
return size;
|
||||
}
|
||||
|
||||
|
||||
nsTArray< nsAutoPtr<Block> > mBlocks;
|
||||
};
|
||||
|
||||
class THEBES_API gfxFontUtils {
|
||||
|
||||
public:
|
||||
|
||||
// for reading big-endian font data on either big or little-endian platforms
|
||||
|
||||
static inline PRUint16
|
||||
ReadShortAt(const PRUint8 *aBuf, PRUint32 aIndex)
|
||||
{
|
||||
return (aBuf[aIndex] << 8) | aBuf[aIndex + 1];
|
||||
}
|
||||
|
||||
static inline PRUint16
|
||||
ReadShortAt16(const PRUint16 *aBuf, PRUint32 aIndex)
|
||||
{
|
||||
const PRUint8 *buf = (PRUint8*) aBuf;
|
||||
PRUint32 index = aIndex << 1;
|
||||
return (buf[index] << 8) | buf[index+1];
|
||||
}
|
||||
|
||||
static inline PRUint32
|
||||
ReadLongAt(const PRUint8 *aBuf, PRUint32 aIndex)
|
||||
{
|
||||
return ((aBuf[aIndex] << 24) | (aBuf[aIndex + 1] << 16) | (aBuf[aIndex + 2] << 8) | (aBuf[aIndex + 3]));
|
||||
}
|
||||
|
||||
static nsresult
|
||||
ReadCMAPTableFormat12(PRUint8 *aBuf, PRInt32 aLength, gfxSparseBitSet& aCharacterMap, std::bitset<128>& aUnicodeRanges);
|
||||
|
||||
static nsresult
|
||||
ReadCMAPTableFormat4(PRUint8 *aBuf, PRInt32 aLength, gfxSparseBitSet& aCharacterMap, std::bitset<128>& aUnicodeRanges);
|
||||
|
||||
static nsresult
|
||||
ReadCMAP(PRUint8 *aBuf, PRUint32 aBufLength, gfxSparseBitSet& aCharacterMap, std::bitset<128>& aUnicodeRanges, PRPackedBool& aUnicodeFont,
|
||||
PRPackedBool& aSymbolFont);
|
||||
|
||||
static inline bool IsJoiner(PRUint32 ch) {
|
||||
return (ch == 0x200C ||
|
||||
ch == 0x200D ||
|
||||
ch == 0x2060);
|
||||
}
|
||||
|
||||
static inline bool IsInvalid(PRUint32 ch) {
|
||||
return (ch == 0xFFFD);
|
||||
}
|
||||
|
||||
static PRUint8 CharRangeBit(PRUint32 ch);
|
||||
|
||||
};
|
||||
|
||||
#endif /* GFX_FONT_UTILS_H */
|
|
@ -44,293 +44,13 @@
|
|||
#include "gfxColor.h"
|
||||
#include "gfxFont.h"
|
||||
#include "gfxMatrix.h"
|
||||
#include "gfxFontUtils.h"
|
||||
|
||||
#include "nsDataHashtable.h"
|
||||
|
||||
#include <usp10.h>
|
||||
#include <cairo-win32.h>
|
||||
|
||||
/* Bug 341128 - w32api defines min/max which causes problems with <bitset> */
|
||||
#ifdef __MINGW32__
|
||||
#undef min
|
||||
#undef max
|
||||
#endif
|
||||
|
||||
#include <bitset>
|
||||
|
||||
#define NO_RANGE_FOUND 126 // bit 126 in the font unicode ranges is required to be 0
|
||||
|
||||
/* Unicode subrange table
|
||||
* from: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/intl/unicode_63ub.asp
|
||||
*
|
||||
* Use something like:
|
||||
* perl -pi -e 's/^(\d+)\s+([\dA-Fa-f]+)\s+-\s+([\dA-Fa-f]+)\s+\b(.*)/ { \1, 0x\2, 0x\3,\"\4\" },/' < unicoderanges.txt
|
||||
* to generate the below list.
|
||||
*/
|
||||
struct UnicodeRangeTableEntry
|
||||
{
|
||||
PRUint8 bit;
|
||||
PRUint32 start;
|
||||
PRUint32 end;
|
||||
const char *info;
|
||||
};
|
||||
|
||||
static const struct UnicodeRangeTableEntry gUnicodeRanges[] = {
|
||||
{ 0, 0x0000, 0x007F, "Basic Latin" },
|
||||
{ 1, 0x0080, 0x00FF, "Latin-1 Supplement" },
|
||||
{ 2, 0x0100, 0x017F, "Latin Extended-A" },
|
||||
{ 3, 0x0180, 0x024F, "Latin Extended-B" },
|
||||
{ 4, 0x0250, 0x02AF, "IPA Extensions" },
|
||||
{ 4, 0x1D00, 0x1D7F, "Phonetic Extensions" },
|
||||
{ 4, 0x1D80, 0x1DBF, "Phonetic Extensions Supplement" },
|
||||
{ 5, 0x02B0, 0x02FF, "Spacing Modifier Letters" },
|
||||
{ 5, 0xA700, 0xA71F, "Modifier Tone Letters" },
|
||||
{ 6, 0x0300, 0x036F, "Spacing Modifier Letters" },
|
||||
{ 6, 0x1DC0, 0x1DFF, "Combining Diacritical Marks Supplement" },
|
||||
{ 7, 0x0370, 0x03FF, "Greek and Coptic" },
|
||||
{ 8, 0x2C80, 0x2CFF, "Coptic" },
|
||||
{ 9, 0x0400, 0x04FF, "Cyrillic" },
|
||||
{ 9, 0x0500, 0x052F, "Cyrillic Supplementary" },
|
||||
{ 10, 0x0530, 0x058F, "Armenian" },
|
||||
{ 11, 0x0590, 0x05FF, "Basic Hebrew" },
|
||||
/* 12 - reserved */
|
||||
{ 13, 0x0600, 0x06FF, "Basic Arabic" },
|
||||
{ 13, 0x0750, 0x077F, "Arabic Supplement" },
|
||||
{ 14, 0x07C0, 0x07FF, "N'Ko" },
|
||||
{ 15, 0x0900, 0x097F, "Devanagari" },
|
||||
{ 16, 0x0980, 0x09FF, "Bengali" },
|
||||
{ 17, 0x0A00, 0x0A7F, "Gurmukhi" },
|
||||
{ 18, 0x0A80, 0x0AFF, "Gujarati" },
|
||||
{ 19, 0x0B00, 0x0B7F, "Oriya" },
|
||||
{ 20, 0x0B80, 0x0BFF, "Tamil" },
|
||||
{ 21, 0x0C00, 0x0C7F, "Telugu" },
|
||||
{ 22, 0x0C80, 0x0CFF, "Kannada" },
|
||||
{ 23, 0x0D00, 0x0D7F, "Malayalam" },
|
||||
{ 24, 0x0E00, 0x0E7F, "Thai" },
|
||||
{ 25, 0x0E80, 0x0EFF, "Lao" },
|
||||
{ 26, 0x10A0, 0x10FF, "Georgian" },
|
||||
{ 26, 0x2D00, 0x2D2F, "Georgian Supplement" },
|
||||
{ 27, 0x1B00, 0x1B7F, "Balinese" },
|
||||
{ 28, 0x1100, 0x11FF, "Hangul Jamo" },
|
||||
{ 29, 0x1E00, 0x1EFF, "Latin Extended Additional" },
|
||||
{ 29, 0x2C60, 0x2C7F, "Latin Extended-C" },
|
||||
{ 30, 0x1F00, 0x1FFF, "Greek Extended" },
|
||||
{ 31, 0x2000, 0x206F, "General Punctuation" },
|
||||
{ 31, 0x2E00, 0x2E7F, "Supplemental Punctuation" },
|
||||
{ 32, 0x2070, 0x209F, "Subscripts and Superscripts" },
|
||||
{ 33, 0x20A0, 0x20CF, "Currency Symbols" },
|
||||
{ 34, 0x20D0, 0x20FF, "Combining Diacritical Marks for Symbols" },
|
||||
{ 35, 0x2100, 0x214F, "Letter-like Symbols" },
|
||||
{ 36, 0x2150, 0x218F, "Number Forms" },
|
||||
{ 37, 0x2190, 0x21FF, "Arrows" },
|
||||
{ 37, 0x27F0, 0x27FF, "Supplemental Arrows-A" },
|
||||
{ 37, 0x2900, 0x297F, "Supplemental Arrows-B" },
|
||||
{ 37, 0x2B00, 0x2BFF, "Miscellaneous Symbols and Arrows" },
|
||||
{ 38, 0x2200, 0x22FF, "Mathematical Operators" },
|
||||
{ 38, 0x27C0, 0x27EF, "Miscellaneous Mathematical Symbols-A" },
|
||||
{ 38, 0x2980, 0x29FF, "Miscellaneous Mathematical Symbols-B" },
|
||||
{ 38, 0x2A00, 0x2AFF, "Supplemental Mathematical Operators" },
|
||||
{ 39, 0x2300, 0x23FF, "Miscellaneous Technical" },
|
||||
{ 40, 0x2400, 0x243F, "Control Pictures" },
|
||||
{ 41, 0x2440, 0x245F, "Optical Character Recognition" },
|
||||
{ 42, 0x2460, 0x24FF, "Enclosed Alphanumerics" },
|
||||
{ 43, 0x2500, 0x257F, "Box Drawing" },
|
||||
{ 44, 0x2580, 0x259F, "Block Elements" },
|
||||
{ 45, 0x25A0, 0x25FF, "Geometric Shapes" },
|
||||
{ 46, 0x2600, 0x26FF, "Miscellaneous Symbols" },
|
||||
{ 47, 0x2700, 0x27BF, "Dingbats" },
|
||||
{ 48, 0x3000, 0x303F, "Chinese, Japanese, and Korean (CJK) Symbols and Punctuation" },
|
||||
{ 49, 0x3040, 0x309F, "Hiragana" },
|
||||
{ 50, 0x30A0, 0x30FF, "Katakana" },
|
||||
{ 50, 0x31F0, 0x31FF, "Katakana Phonetic Extensions" },
|
||||
{ 51, 0x3100, 0x312F, "Bopomofo" },
|
||||
{ 51, 0x31A0, 0x31BF, "Extended Bopomofo" },
|
||||
{ 52, 0x3130, 0x318F, "Hangul Compatibility Jamo" },
|
||||
{ 53, 0xA840, 0xA87F, "Phags-pa" },
|
||||
{ 54, 0x3200, 0x32FF, "Enclosed CJK Letters and Months" },
|
||||
{ 55, 0x3300, 0x33FF, "CJK Compatibility" },
|
||||
{ 56, 0xAC00, 0xD7A3, "Hangul" },
|
||||
{ 57, 0xD800, 0xDFFF, "Surrogates. Note that setting this bit implies that there is at least one supplementary code point beyond the Basic Multilingual Plane (BMP) that is supported by this font. See Surrogates and Supplementary Characters." },
|
||||
{ 58, 0x10900, 0x1091F, "Phoenician" },
|
||||
{ 59, 0x2E80, 0x2EFF, "CJK Radicals Supplement" },
|
||||
{ 59, 0x2F00, 0x2FDF, "Kangxi Radicals" },
|
||||
{ 59, 0x2FF0, 0x2FFF, "Ideographic Description Characters" },
|
||||
{ 59, 0x3190, 0x319F, "Kanbun" },
|
||||
{ 59, 0x3400, 0x4DBF, "CJK Unified Ideographs Extension A" },
|
||||
{ 59, 0x4E00, 0x9FFF, "CJK Unified Ideographs" },
|
||||
{ 59, 0x20000, 0x2A6DF, "CJK Unified Ideographs Extension B" },
|
||||
{ 60, 0xE000, 0xF8FF, "Private Use (Plane 0)" },
|
||||
{ 61, 0x31C0, 0x31EF, "CJK Base Strokes" },
|
||||
{ 61, 0xF900, 0xFAFF, "CJK Compatibility Ideographs" },
|
||||
{ 61, 0x2F800, 0x2FA1F, "CJK Compatibility Ideographs Supplement" },
|
||||
{ 62, 0xFB00, 0xFB4F, "Alphabetical Presentation Forms" },
|
||||
{ 63, 0xFB50, 0xFDFF, "Arabic Presentation Forms-A" },
|
||||
{ 64, 0xFE20, 0xFE2F, "Combining Half Marks" },
|
||||
{ 65, 0xFE10, 0xFE1F, "Vertical Forms" },
|
||||
{ 65, 0xFE30, 0xFE4F, "CJK Compatibility Forms" },
|
||||
{ 66, 0xFE50, 0xFE6F, "Small Form Variants" },
|
||||
{ 67, 0xFE70, 0xFEFE, "Arabic Presentation Forms-B" },
|
||||
{ 68, 0xFF00, 0xFFEF, "Halfwidth and Fullwidth Forms" },
|
||||
{ 69, 0xFFF0, 0xFFFF, "Specials" },
|
||||
{ 70, 0x0F00, 0x0FFF, "Tibetan" },
|
||||
{ 71, 0x0700, 0x074F, "Syriac" },
|
||||
{ 72, 0x0780, 0x07BF, "Thaana" },
|
||||
{ 73, 0x0D80, 0x0DFF, "Sinhala" },
|
||||
{ 74, 0x1000, 0x109F, "Myanmar" },
|
||||
{ 75, 0x1200, 0x137F, "Ethiopic" },
|
||||
{ 75, 0x1380, 0x139F, "Ethiopic Supplement" },
|
||||
{ 75, 0x2D80, 0x2DDF, "Ethiopic Extended" },
|
||||
{ 76, 0x13A0, 0x13FF, "Cherokee" },
|
||||
{ 77, 0x1400, 0x167F, "Canadian Aboriginal Syllabics" },
|
||||
{ 78, 0x1680, 0x169F, "Ogham" },
|
||||
{ 79, 0x16A0, 0x16FF, "Runic" },
|
||||
{ 80, 0x1780, 0x17FF, "Khmer" },
|
||||
{ 80, 0x19E0, 0x19FF, "Khmer Symbols" },
|
||||
{ 81, 0x1800, 0x18AF, "Mongolian" },
|
||||
{ 82, 0x2800, 0x28FF, "Braille" },
|
||||
{ 83, 0xA000, 0xA48F, "Yi" },
|
||||
{ 83, 0xA490, 0xA4CF, "Yi Radicals" },
|
||||
{ 84, 0x1700, 0x171F, "Tagalog" },
|
||||
{ 84, 0x1720, 0x173F, "Hanunoo" },
|
||||
{ 84, 0x1740, 0x175F, "Buhid" },
|
||||
{ 84, 0x1760, 0x177F, "Tagbanwa" },
|
||||
{ 85, 0x10300, 0x1032F, "Old Italic" },
|
||||
{ 86, 0x10330, 0x1034F, "Gothic" },
|
||||
{ 87, 0x10440, 0x1044F, "Deseret" },
|
||||
{ 88, 0x1D000, 0x1D0FF, "Byzantine Musical Symbols" },
|
||||
{ 88, 0x1D100, 0x1D1FF, "Musical Symbols" },
|
||||
{ 88, 0x1D200, 0x1D24F, "Ancient Greek Musical Notation" },
|
||||
{ 89, 0x1D400, 0x1D7FF, "Mathematical Alphanumeric Symbols" },
|
||||
{ 90, 0xFF000, 0xFFFFD, "Private Use (Plane 15)" },
|
||||
{ 90, 0x100000, 0x10FFFD, "Private Use (Plane 16)" },
|
||||
{ 91, 0xFE00, 0xFE0F, "Variation Selectors" },
|
||||
{ 91, 0xE0100, 0xE01EF, "Variation Selectors Supplement" },
|
||||
{ 92, 0xE0000, 0xE007F, "Tags" },
|
||||
{ 93, 0x1900, 0x194F, "Limbu" },
|
||||
{ 94, 0x1950, 0x197F, "Tai Le" },
|
||||
{ 95, 0x1980, 0x19DF, "New Tai Lue" },
|
||||
{ 96, 0x1A00, 0x1A1F, "Buginese" },
|
||||
{ 97, 0x2C00, 0x2C5F, "Glagolitic" },
|
||||
{ 98, 0x2D40, 0x2D7F, "Tifinagh" },
|
||||
{ 99, 0x4DC0, 0x4DFF, "Yijing Hexagram Symbols" },
|
||||
{ 100, 0xA800, 0xA82F, "Syloti Nagri" },
|
||||
{ 101, 0x10000, 0x1007F, "Linear B Syllabary" },
|
||||
{ 101, 0x10080, 0x100FF, "Linear B Ideograms" },
|
||||
{ 101, 0x10100, 0x1013F, "Aegean Numbers" },
|
||||
{ 102, 0x10140, 0x1018F, "Ancient Greek Numbers" },
|
||||
{ 103, 0x10380, 0x1039F, "Ugaritic" },
|
||||
{ 104, 0x103A0, 0x103DF, "Old Persian" },
|
||||
{ 105, 0x10450, 0x1047F, "Shavian" },
|
||||
{ 106, 0x10480, 0x104AF, "Osmanya" },
|
||||
{ 107, 0x10800, 0x1083F, "Cypriot Syllabary" },
|
||||
{ 108, 0x10A00, 0x10A5F, "Kharoshthi" },
|
||||
{ 109, 0x1D300, 0x1D35F, "Tai Xuan Jing Symbols" },
|
||||
{ 110, 0x12000, 0x123FF, "Cuneiform" },
|
||||
{ 110, 0x12400, 0x1247F, "Cuneiform Numbers and Punctuation" },
|
||||
{ 111, 0x1D360, 0x1D37F, "Counting Rod Numerals" }
|
||||
};
|
||||
|
||||
static PRUint8 CharRangeBit(PRUint32 ch) {
|
||||
const PRUint32 n = sizeof(gUnicodeRanges) / sizeof(struct UnicodeRangeTableEntry);
|
||||
|
||||
for (PRUint32 i = 0; i < n; ++i)
|
||||
if (ch >= gUnicodeRanges[i].start && ch <= gUnicodeRanges[i].end)
|
||||
return gUnicodeRanges[i].bit;
|
||||
|
||||
return NO_RANGE_FOUND;
|
||||
}
|
||||
|
||||
|
||||
class gfxSparseBitSet {
|
||||
private:
|
||||
enum { BLOCK_SIZE = 32 };
|
||||
enum { BLOCK_SIZE_BITS = BLOCK_SIZE * 8 };
|
||||
|
||||
struct Block {
|
||||
Block(unsigned char memsetValue = 0) { memset(mBits, memsetValue, BLOCK_SIZE); }
|
||||
PRUint8 mBits[BLOCK_SIZE];
|
||||
};
|
||||
|
||||
public:
|
||||
PRBool test(PRUint32 aIndex) {
|
||||
PRUint32 blockIndex = aIndex/BLOCK_SIZE_BITS;
|
||||
if (blockIndex >= mBlocks.Length())
|
||||
return PR_FALSE;
|
||||
Block *block = mBlocks[blockIndex];
|
||||
if (!block)
|
||||
return PR_FALSE;
|
||||
return ((block->mBits[(aIndex/8) & (BLOCK_SIZE - 1)]) & (1 << (aIndex & 0x7))) != 0;
|
||||
}
|
||||
|
||||
void set(PRUint32 aIndex) {
|
||||
PRUint32 blockIndex = aIndex/BLOCK_SIZE_BITS;
|
||||
if (blockIndex >= mBlocks.Length()) {
|
||||
nsAutoPtr<Block> *blocks = mBlocks.AppendElements(blockIndex + 1 - mBlocks.Length());
|
||||
if (NS_UNLIKELY(!blocks)) // OOM
|
||||
return;
|
||||
}
|
||||
Block *block = mBlocks[blockIndex];
|
||||
if (!block) {
|
||||
block = new Block;
|
||||
if (NS_UNLIKELY(!block)) // OOM
|
||||
return;
|
||||
mBlocks[blockIndex] = block;
|
||||
}
|
||||
block->mBits[(aIndex/8) & (BLOCK_SIZE - 1)] |= 1 << (aIndex & 0x7);
|
||||
}
|
||||
|
||||
void SetRange(PRUint32 aStart, PRUint32 aEnd) {
|
||||
const PRUint32 startIndex = aStart/BLOCK_SIZE_BITS;
|
||||
const PRUint32 endIndex = aEnd/BLOCK_SIZE_BITS;
|
||||
|
||||
if (endIndex >= mBlocks.Length()) {
|
||||
PRUint32 numNewBlocks = endIndex + 1 - mBlocks.Length();
|
||||
nsAutoPtr<Block> *blocks = mBlocks.AppendElements(numNewBlocks);
|
||||
if (NS_UNLIKELY(!blocks)) // OOM
|
||||
return;
|
||||
}
|
||||
|
||||
for (PRUint32 i = startIndex; i <= endIndex; ++i) {
|
||||
const PRUint32 blockFirstBit = i * BLOCK_SIZE_BITS;
|
||||
const PRUint32 blockLastBit = blockFirstBit + BLOCK_SIZE_BITS - 1;
|
||||
|
||||
Block *block = mBlocks[i];
|
||||
if (!block) {
|
||||
PRBool fullBlock = PR_FALSE;
|
||||
if (aStart <= blockFirstBit && aEnd >= blockLastBit)
|
||||
fullBlock = PR_TRUE;
|
||||
|
||||
block = new Block(fullBlock ? 0xFF : 0);
|
||||
|
||||
if (NS_UNLIKELY(!block)) // OOM
|
||||
return;
|
||||
mBlocks[i] = block;
|
||||
|
||||
if (fullBlock)
|
||||
continue;
|
||||
}
|
||||
|
||||
const PRUint32 start = aStart > blockFirstBit ? aStart - blockFirstBit : 0;
|
||||
const PRUint32 end = PR_MIN(aEnd - blockFirstBit, BLOCK_SIZE_BITS - 1);
|
||||
|
||||
for (PRUint32 bit = start; bit <= end; ++bit) {
|
||||
block->mBits[bit/8] |= 1 << (bit & 0x7);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PRUint32 GetSize() {
|
||||
PRUint32 size = 0;
|
||||
for (PRUint32 i = 0; i < mBlocks.Length(); i++)
|
||||
if (mBlocks[i])
|
||||
size += sizeof(Block);
|
||||
return size;
|
||||
}
|
||||
|
||||
|
||||
nsTArray< nsAutoPtr<Block> > mBlocks;
|
||||
};
|
||||
|
||||
/**
|
||||
* FontEntry is a class that describes one of the fonts on the users system
|
||||
* It contains information such as the name, font type, charset table and unicode ranges.
|
||||
|
|
|
@ -29,6 +29,7 @@ CPPSRCS = \
|
|||
gfxFont.cpp \
|
||||
gfxFontMissingGlyphs.cpp \
|
||||
gfxFontTest.cpp \
|
||||
gfxFontUtils.cpp \
|
||||
gfxMatrix.cpp \
|
||||
gfxPath.cpp \
|
||||
gfxPattern.cpp \
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
* Contributor(s):
|
||||
* Vladimir Vukicevic <vladimir@pobox.com>
|
||||
* Masayuki Nakano <masayuki@d-toybox.com>
|
||||
* John Daggett <jdaggett@mozilla.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
|
@ -50,6 +51,7 @@
|
|||
#include "gfxAtsuiFonts.h"
|
||||
|
||||
#include "gfxFontTest.h"
|
||||
#include "gfxFontUtils.h"
|
||||
|
||||
#include "cairo-atsui.h"
|
||||
|
||||
|
@ -58,6 +60,7 @@
|
|||
|
||||
#include "nsIPrefBranch.h"
|
||||
#include "nsIPrefService.h"
|
||||
#include "nsIPrefLocalizedString.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
#include "nsUnicodeRange.h"
|
||||
#include "nsCRT.h"
|
||||
|
@ -85,6 +88,84 @@ OSStatus ATSInitializeGlyphVector(int size, void *glyphVectorPtr);
|
|||
OSStatus ATSClearGlyphVector(void *glyphVectorPtr);
|
||||
#endif
|
||||
|
||||
// The lang names for eFontPrefLang
|
||||
// this needs to match the list of pref font.default.xx entries listed in all.js!
|
||||
static const char *gPrefLangNames[] = {
|
||||
"x-western",
|
||||
"x-central-euro",
|
||||
"ja",
|
||||
"zh-TW",
|
||||
"zh-CN",
|
||||
"zh-HK",
|
||||
"ko",
|
||||
"x-cyrillic",
|
||||
"x-baltic",
|
||||
"el",
|
||||
"tr",
|
||||
"th",
|
||||
"he",
|
||||
"ar",
|
||||
"x-devanagari",
|
||||
"x-tamil",
|
||||
"x-armn",
|
||||
"x-beng",
|
||||
"x-cans",
|
||||
"x-ethi",
|
||||
"x-geor",
|
||||
"x-gujr",
|
||||
"x-guru",
|
||||
"x-khmr",
|
||||
"x-mlym",
|
||||
"x-unicode",
|
||||
"x-user-def"
|
||||
};
|
||||
|
||||
// The lang IDs for font prefs
|
||||
// this needs to match the list of pref font.default.xx entries listed in all.js!
|
||||
enum eFontPrefLang {
|
||||
eFontPrefLang_Western = 0,
|
||||
eFontPrefLang_CentEuro = 1,
|
||||
eFontPrefLang_Japanese = 2,
|
||||
eFontPrefLang_ChineseTW = 3,
|
||||
eFontPrefLang_ChineseCN = 4,
|
||||
eFontPrefLang_ChineseHK = 5,
|
||||
eFontPrefLang_Korean = 6,
|
||||
eFontPrefLang_Cyrillic = 7,
|
||||
eFontPrefLang_Baltic = 8,
|
||||
eFontPrefLang_Greek = 9,
|
||||
eFontPrefLang_Turkish = 10,
|
||||
eFontPrefLang_Thai = 11,
|
||||
eFontPrefLang_Hebrew = 12,
|
||||
eFontPrefLang_Arabic = 13,
|
||||
eFontPrefLang_Devanagari = 14,
|
||||
eFontPrefLang_Tamil = 15,
|
||||
eFontPrefLang_Armenian = 16,
|
||||
eFontPrefLang_Bengali = 17,
|
||||
eFontPrefLang_Canadian = 18,
|
||||
eFontPrefLang_Ethiopic = 19,
|
||||
eFontPrefLang_Georgian = 20,
|
||||
eFontPrefLang_Gujarati = 21,
|
||||
eFontPrefLang_Gurmukhi = 22,
|
||||
eFontPrefLang_Khmer = 23,
|
||||
eFontPrefLang_Malayalam = 24,
|
||||
|
||||
eFontPrefLang_LangCount = 25, // except Others and UserDefined.
|
||||
|
||||
eFontPrefLang_Others = 25, // x-unicode
|
||||
eFontPrefLang_UserDefined = 26,
|
||||
|
||||
eFontPrefLang_CJKSet = 27, // special code for CJK set
|
||||
eFontPrefLang_AllCount = 28
|
||||
};
|
||||
|
||||
static nsresult AppendAllPrefFonts(nsTArray<nsRefPtr<gfxFont> > *aFonts,
|
||||
eFontPrefLang aLang, PRUint32& didAppendBits, const gfxFontStyle *aStyle);
|
||||
|
||||
static eFontPrefLang GetFontPrefLangFor(const char* aLang);
|
||||
eFontPrefLang GetFontPrefLangFor(PRUint8 aUnicodeRange);
|
||||
|
||||
|
||||
|
||||
gfxAtsuiFont::gfxAtsuiFont(ATSUFontID fontID,
|
||||
const nsAString& name,
|
||||
const gfxFontStyle *fontStyle)
|
||||
|
@ -97,7 +178,9 @@ gfxAtsuiFont::gfxAtsuiFont(ATSUFontID fontID,
|
|||
InitMetrics(fontID, fontRef);
|
||||
|
||||
mFontFace = cairo_atsui_font_face_create_for_atsu_font_id(mATSUFontID);
|
||||
|
||||
|
||||
mFontEntry = gfxQuartzFontCache::SharedFontCache()->FindFontEntry(mATSUFontID);
|
||||
|
||||
cairo_matrix_t sizeMatrix, ctm;
|
||||
cairo_matrix_init_identity(&ctm);
|
||||
cairo_matrix_init_scale(&sizeMatrix, mAdjustedSize, mAdjustedSize);
|
||||
|
@ -315,26 +398,6 @@ gfxAtsuiFont::GetMetrics()
|
|||
return mMetrics;
|
||||
}
|
||||
|
||||
static nsresult
|
||||
CreateFontFallbacksFromFontList(nsTArray< nsRefPtr<gfxFont> > *aFonts,
|
||||
ATSUFontFallbacks *aFallbacks,
|
||||
ATSUFontFallbackMethod aMethod)
|
||||
{
|
||||
// Create the fallback structure
|
||||
OSStatus status = ::ATSUCreateFontFallbacks(aFallbacks);
|
||||
NS_ENSURE_TRUE(status == noErr, NS_ERROR_FAILURE);
|
||||
|
||||
nsAutoTArray<ATSUFontID,16> fids;
|
||||
|
||||
for (unsigned int i = 0; i < aFonts->Length(); i++) {
|
||||
gfxAtsuiFont* atsuiFont = static_cast<gfxAtsuiFont*>(aFonts->ElementAt(i).get());
|
||||
fids.AppendElement(atsuiFont->GetATSUFontID());
|
||||
}
|
||||
status = ::ATSUSetObjFontFallbacks(*aFallbacks, fids.Length(), fids.Elements(), aMethod);
|
||||
|
||||
return status == noErr ? NS_OK : NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
void
|
||||
gfxAtsuiFont::SetupGlyphExtents(gfxContext *aContext, PRUint32 aGlyphID,
|
||||
PRBool aNeedTight, gfxGlyphExtents *aExtents)
|
||||
|
@ -351,7 +414,7 @@ gfxAtsuiFont::SetupGlyphExtents(gfxContext *aContext, PRUint32 aGlyphID,
|
|||
-metrics.topLeft.y + metrics.height <= mMetrics.maxAscent &&
|
||||
metrics.topLeft.y <= mMetrics.maxDescent) {
|
||||
PRUint32 appUnitsWidth =
|
||||
PRUint32(NS_ceil((metrics.topLeft.x + metrics.width)*appUnitsPerDevUnit));
|
||||
PRUint32(NS_ceil((metrics.topLeft.x + metrics.width)*appUnitsPerDevUnit));
|
||||
if (appUnitsWidth < gfxGlyphExtents::INVALID_WIDTH) {
|
||||
aExtents->SetContainedGlyphWidthAppUnits(aGlyphID, PRUint16(appUnitsWidth));
|
||||
return;
|
||||
|
@ -380,6 +443,9 @@ gfxAtsuiFont::HasMirroringInfo()
|
|||
return mHasMirroring;
|
||||
}
|
||||
|
||||
PRBool gfxAtsuiFont::TestCharacterMap(PRUint32 aCh) {
|
||||
return mFontEntry->TestCharacterMap(aCh);
|
||||
}
|
||||
|
||||
/**
|
||||
* Look up the font in the gfxFont cache. If we don't find it, create one.
|
||||
|
@ -426,10 +492,9 @@ gfxAtsuiFontGroup::gfxAtsuiFontGroup(const nsAString& families,
|
|||
// a specific langGroup. Let's just pick the default OSX
|
||||
// user font.
|
||||
ATSUFontID fontID = gfxQuartzFontCache::SharedFontCache()->GetDefaultATSUFontID (aStyle);
|
||||
NS_ASSERTION(fontID != kATSUInvalidFontID, "invalid default font returned by GetDefaultATSUFontID");
|
||||
GetOrMakeFont(fontID, aStyle, &mFonts);
|
||||
}
|
||||
|
||||
CreateFontFallbacksFromFontList(&mFonts, &mFallbacks, kATSUSequentialFallbacksExclusive);
|
||||
}
|
||||
|
||||
PRBool
|
||||
|
@ -451,11 +516,6 @@ gfxAtsuiFontGroup::FindATSUFont(const nsAString& aName,
|
|||
return PR_TRUE;
|
||||
}
|
||||
|
||||
gfxAtsuiFontGroup::~gfxAtsuiFontGroup()
|
||||
{
|
||||
ATSUDisposeFontFallbacks(mFallbacks);
|
||||
}
|
||||
|
||||
gfxFontGroup *
|
||||
gfxAtsuiFontGroup::Copy(const gfxFontStyle *aStyle)
|
||||
{
|
||||
|
@ -686,6 +746,71 @@ gfxAtsuiFontGroup::HasFont(ATSUFontID fid)
|
|||
return PR_FALSE;
|
||||
}
|
||||
|
||||
already_AddRefed<gfxAtsuiFont>
|
||||
gfxAtsuiFontGroup::FindFontForChar(PRUint32 aCh, PRUint32 aPrevCh, PRUint32 aNextCh, gfxAtsuiFont* aPrevMatchedFont)
|
||||
{
|
||||
nsRefPtr<gfxAtsuiFont> selectedFont;
|
||||
|
||||
// if this character or the next one is a joiner use the
|
||||
// same font as the previous range if we can
|
||||
if (gfxFontUtils::IsJoiner(aCh) || gfxFontUtils::IsJoiner(aPrevCh) || gfxFontUtils::IsJoiner(aNextCh)) {
|
||||
if (aPrevMatchedFont && aPrevMatchedFont->TestCharacterMap(aCh)) {
|
||||
selectedFont = aPrevMatchedFont;
|
||||
return selectedFont.forget();
|
||||
}
|
||||
}
|
||||
|
||||
// 1. check fonts in the font group
|
||||
selectedFont = WhichFontSupportsChar(mFonts, aCh);
|
||||
|
||||
// don't look in other fonts if the character is in a Private Use Area
|
||||
if ((aCh >= 0xE000 && aCh <= 0xF8FF) ||
|
||||
(aCh >= 0xF0000 && aCh <= 0x10FFFD))
|
||||
return selectedFont.forget();
|
||||
if ( selectedFont )
|
||||
return selectedFont.forget();
|
||||
|
||||
// 2. search pref fonts if none of the font group fonts match
|
||||
if (aCh <= 0xFFFF) { // FindCharUnicodeRange only supports BMP character points and there are no non-BMP fonts in prefs
|
||||
nsresult rv;
|
||||
PRUint32 unicodeRange = FindCharUnicodeRange(aCh);
|
||||
PRUint32 didAppendFonts = 0;
|
||||
|
||||
nsAutoTArray<nsRefPtr<gfxFont>, 15> prefFonts;
|
||||
|
||||
// xxx - god this sucks to be doing this per-character in the fallback case
|
||||
eFontPrefLang prefLang = GetFontPrefLangFor(unicodeRange);
|
||||
|
||||
rv = AppendAllPrefFonts(&prefFonts, prefLang, didAppendFonts, GetStyle());
|
||||
if (!NS_FAILED(rv)) {
|
||||
selectedFont = WhichFontSupportsChar(prefFonts, aCh);
|
||||
if (selectedFont) {
|
||||
return selectedFont.forget();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 3. use fallback fonts
|
||||
// -- before searching for something else check the font used for the previous character
|
||||
if (!selectedFont && aPrevMatchedFont && aPrevMatchedFont->TestCharacterMap(aCh)) {
|
||||
selectedFont = aPrevMatchedFont;
|
||||
return selectedFont.forget();
|
||||
}
|
||||
|
||||
// -- otherwise look for other stuff
|
||||
if (!selectedFont) {
|
||||
FontEntry *fe;
|
||||
|
||||
fe = gfxQuartzFontCache::SharedFontCache()->FindFontForChar(aCh, aPrevMatchedFont);
|
||||
if (fe) {
|
||||
selectedFont = FindFontFor(fe->GetFontID());
|
||||
return selectedFont.forget();
|
||||
}
|
||||
}
|
||||
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple wrapper for ATSU "direct data arrays"
|
||||
*/
|
||||
|
@ -1026,74 +1151,6 @@ PostLayoutOperationCallback(ATSULayoutOperationSelector iCurrentOperation,
|
|||
return noErr;
|
||||
}
|
||||
|
||||
// The lang IDs for font prefs
|
||||
enum eFontPrefLang {
|
||||
eFontPrefLang_Western = 0,
|
||||
eFontPrefLang_CentEuro = 1,
|
||||
eFontPrefLang_Japanese = 2,
|
||||
eFontPrefLang_ChineseTW = 3,
|
||||
eFontPrefLang_ChineseCN = 4,
|
||||
eFontPrefLang_ChineseHK = 5,
|
||||
eFontPrefLang_Korean = 6,
|
||||
eFontPrefLang_Cyrillic = 7,
|
||||
eFontPrefLang_Baltic = 8,
|
||||
eFontPrefLang_Greek = 9,
|
||||
eFontPrefLang_Turkish = 10,
|
||||
eFontPrefLang_Thai = 11,
|
||||
eFontPrefLang_Hebrew = 12,
|
||||
eFontPrefLang_Arabic = 13,
|
||||
eFontPrefLang_Devanagari = 14,
|
||||
eFontPrefLang_Tamil = 15,
|
||||
eFontPrefLang_Armenian = 16,
|
||||
eFontPrefLang_Bengali = 17,
|
||||
eFontPrefLang_Canadian = 18,
|
||||
eFontPrefLang_Ethiopic = 19,
|
||||
eFontPrefLang_Georgian = 20,
|
||||
eFontPrefLang_Gujarati = 21,
|
||||
eFontPrefLang_Gurmukhi = 22,
|
||||
eFontPrefLang_Khmer = 23,
|
||||
eFontPrefLang_Malayalam = 24,
|
||||
|
||||
eFontPrefLang_LangCount = 25, // except Others and UserDefined.
|
||||
|
||||
eFontPrefLang_Others = 25, // x-unicode
|
||||
eFontPrefLang_UserDefined = 26,
|
||||
|
||||
eFontPrefLang_CJKSet = 27, // special code for CJK set
|
||||
eFontPrefLang_AllCount = 28
|
||||
};
|
||||
|
||||
// The lang names for eFontPrefLang
|
||||
static const char *gPrefLangNames[] = {
|
||||
"x-western",
|
||||
"x-central-euro",
|
||||
"ja",
|
||||
"zh-TW",
|
||||
"zh-CN",
|
||||
"zh-HK",
|
||||
"ko",
|
||||
"x-cyrillic",
|
||||
"x-baltic",
|
||||
"el",
|
||||
"tr",
|
||||
"th",
|
||||
"he",
|
||||
"ar",
|
||||
"x-devanagari",
|
||||
"x-tamil",
|
||||
"x-armn",
|
||||
"x-beng",
|
||||
"x-cans",
|
||||
"x-ethi",
|
||||
"x-geor",
|
||||
"x-gujr",
|
||||
"x-guru",
|
||||
"x-khmr",
|
||||
"x-mlym",
|
||||
"x-unicode",
|
||||
"x-user-def"
|
||||
};
|
||||
|
||||
static eFontPrefLang
|
||||
GetFontPrefLangFor(const char* aLang)
|
||||
{
|
||||
|
@ -1202,16 +1259,21 @@ AppendCJKPrefFonts(nsTArray<nsRefPtr<gfxFont> > *aFonts,
|
|||
PRUint32& didAppendBits,
|
||||
const gfxFontStyle *aStyle)
|
||||
{
|
||||
nsCOMPtr<nsIPrefService> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
|
||||
NS_ENSURE_TRUE(prefs, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
nsCOMPtr<nsIPrefBranch> prefBranch;
|
||||
prefs->GetBranch(nsnull, getter_AddRefs(prefBranch));
|
||||
NS_ENSURE_TRUE(prefBranch, NS_ERROR_OUT_OF_MEMORY);
|
||||
nsCOMPtr<nsIPrefBranch> prefs(do_GetService(NS_PREFSERVICE_CONTRACTID));
|
||||
|
||||
// Add the CJK pref fonts from accept languages, the order should be same order
|
||||
nsXPIDLCString list;
|
||||
nsresult rv = prefBranch->GetCharPref("intl.accept_languages", getter_Copies(list));
|
||||
nsCAutoString list;
|
||||
nsresult rv;
|
||||
if (prefs) {
|
||||
nsCOMPtr<nsIPrefLocalizedString> prefString;
|
||||
rv = prefs->GetComplexValue("intl.accept_languages", NS_GET_IID(nsIPrefLocalizedString), getter_AddRefs(prefString));
|
||||
if (prefString) {
|
||||
nsAutoString temp;
|
||||
prefString->ToString(getter_Copies(temp));
|
||||
LossyCopyUTF16toASCII(temp, list);
|
||||
}
|
||||
}
|
||||
|
||||
if (NS_SUCCEEDED(rv) && !list.IsEmpty()) {
|
||||
const char kComma = ',';
|
||||
const char *p, *p_end;
|
||||
|
@ -1271,6 +1333,25 @@ AppendCJKPrefFonts(nsTArray<nsRefPtr<gfxFont> > *aFonts,
|
|||
return rv;
|
||||
}
|
||||
|
||||
static nsresult
|
||||
AppendAllPrefFonts(nsTArray<nsRefPtr<gfxFont> > *aFonts,
|
||||
eFontPrefLang aLang,
|
||||
PRUint32& didAppendBits,
|
||||
const gfxFontStyle *aStyle)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
if (aLang == eFontPrefLang_CJKSet)
|
||||
rv = AppendCJKPrefFonts(aFonts, didAppendBits, aStyle);
|
||||
else
|
||||
rv = AppendPrefFonts(aFonts, aLang, didAppendBits, aStyle);
|
||||
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
rv = AppendPrefFonts(aFonts, eFontPrefLang_Others, didAppendBits, aStyle);
|
||||
return rv;
|
||||
}
|
||||
|
||||
static void
|
||||
DisableOptionalLigaturesInStyle(ATSUStyle aStyle)
|
||||
{
|
||||
|
@ -1340,6 +1421,105 @@ static void MirrorSubstring(ATSUTextLayout layout, nsAutoArrayPtr<PRUnichar>& mi
|
|||
}
|
||||
}
|
||||
|
||||
// match fonts with character sequence based on font cmap tables
|
||||
class CmapFontMatcher {
|
||||
public:
|
||||
CmapFontMatcher(const PRUnichar *aString, PRUint32 aBeginOffset, PRUint32 aEndOffset, gfxAtsuiFontGroup* aFontGroup) :
|
||||
mString(aString), mOffset(aBeginOffset), mPrevOffset(aBeginOffset), mEndOffset(aEndOffset), mPrevCh(0), mFirstPass(PR_TRUE), mFontGroup(aFontGroup), mMatchedFont(0), mNextMatchedFont(0)
|
||||
{}
|
||||
|
||||
// match the next substring that uses the same font, returns the length matched
|
||||
PRUint32 MatchNextRange()
|
||||
{
|
||||
PRUint32 matchStartOffset, chStartOffset, ch, nextCh;
|
||||
nsRefPtr<gfxAtsuiFont> font;
|
||||
|
||||
matchStartOffset = mPrevOffset;
|
||||
|
||||
if ( !mFirstPass ) {
|
||||
mMatchedFont = mNextMatchedFont;
|
||||
}
|
||||
|
||||
while ( mOffset < mEndOffset ) {
|
||||
chStartOffset = mOffset;
|
||||
|
||||
// set up current ch
|
||||
ch = mString[mOffset];
|
||||
if ((mOffset+1 < mEndOffset) && NS_IS_HIGH_SURROGATE(ch) && NS_IS_LOW_SURROGATE(mString[mOffset+1])) {
|
||||
mOffset++;
|
||||
ch = SURROGATE_TO_UCS4(ch, mString[mOffset]);
|
||||
}
|
||||
|
||||
// set up next ch
|
||||
nextCh = 0;
|
||||
if (mOffset+1 < mEndOffset) {
|
||||
nextCh = mString[mOffset+1];
|
||||
if ((mOffset+2 < mEndOffset) && NS_IS_HIGH_SURROGATE(nextCh) && NS_IS_LOW_SURROGATE(mString[mOffset+2]))
|
||||
nextCh = SURROGATE_TO_UCS4(nextCh, mString[mOffset+2]);
|
||||
}
|
||||
|
||||
// find the font for this char
|
||||
font = mFontGroup->FindFontForChar(ch, mPrevCh, nextCh, mMatchedFont);
|
||||
mOffset++;
|
||||
mPrevCh = ch;
|
||||
|
||||
// no previous match, set one up
|
||||
if ( mFirstPass ) {
|
||||
mMatchedFont = font;
|
||||
mFirstPass = PR_FALSE;
|
||||
} else if ( font != mMatchedFont ) {
|
||||
mPrevOffset = chStartOffset;
|
||||
mNextMatchedFont = font;
|
||||
return chStartOffset - matchStartOffset;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// reached the end of the string
|
||||
mPrevOffset = mEndOffset;
|
||||
mNextMatchedFont = nsnull;
|
||||
return mOffset - matchStartOffset;
|
||||
}
|
||||
|
||||
inline gfxAtsuiFont* MatchedFont() { return mMatchedFont.get(); }
|
||||
|
||||
private:
|
||||
const PRUnichar *mString;
|
||||
PRUint32 mOffset;
|
||||
PRUint32 mPrevOffset;
|
||||
PRUint32 mEndOffset;
|
||||
PRUint32 mPrevCh;
|
||||
PRBool mFirstPass;
|
||||
gfxAtsuiFontGroup *mFontGroup;
|
||||
nsRefPtr<gfxAtsuiFont> mMatchedFont;
|
||||
nsRefPtr<gfxAtsuiFont> mNextMatchedFont;
|
||||
};
|
||||
|
||||
|
||||
static ATSUStyle
|
||||
SetLayoutRangeToFont(ATSUTextLayout layout, ATSUStyle mainStyle, UniCharArrayOffset offset,
|
||||
UniCharCount length, ATSUFontID fontID)
|
||||
{
|
||||
ATSUStyle subStyle;
|
||||
ATSUCreateStyle (&subStyle);
|
||||
ATSUCopyAttributes (mainStyle, subStyle);
|
||||
|
||||
ATSUAttributeTag fontTags[] = { kATSUFontTag };
|
||||
ByteCount fontArgSizes[] = { sizeof(ATSUFontID) };
|
||||
ATSUAttributeValuePtr fontArgs[] = { &fontID };
|
||||
|
||||
ATSUSetAttributes (subStyle, 1, fontTags, fontArgSizes, fontArgs);
|
||||
|
||||
// apply the new style to the layout for the changed substring
|
||||
ATSUSetRunStyle (layout, subStyle, offset, length);
|
||||
|
||||
return subStyle;
|
||||
}
|
||||
|
||||
#ifdef DUMP_TEXT_RUNS
|
||||
static PRLogModuleInfo *gAtsuiTextRunLog = PR_NewLogModule("atsuiTextRun");
|
||||
#endif
|
||||
|
||||
PRBool
|
||||
gfxAtsuiFontGroup::InitTextRun(gfxTextRun *aRun,
|
||||
const PRUnichar *aString, PRUint32 aLength,
|
||||
|
@ -1358,7 +1538,8 @@ gfxAtsuiFontGroup::InitTextRun(gfxTextRun *aRun,
|
|||
#ifdef DUMP_TEXT_RUNS
|
||||
NS_ConvertUTF16toUTF8 str(realString, aSegmentLength);
|
||||
NS_ConvertUTF16toUTF8 families(mFamilies);
|
||||
printf("%p(%s) TEXTRUN \"%s\" ENDTEXTRUN\n", this, families.get(), str.get());
|
||||
PR_LOG(gAtsuiTextRunLog, PR_LOG_DEBUG, ("InitTextRun %p fontgroup %p (%s) len %d TEXTRUN \"%s\" ENDTEXTRUN\n", aRun, this, families.get(), aSegmentLength, str.get()) );
|
||||
PR_LOG(gAtsuiTextRunLog, PR_LOG_DEBUG, ("InitTextRun font: %s\n", NS_ConvertUTF16toUTF8(firstFont->GetUniqueName()).get()) );
|
||||
#endif
|
||||
|
||||
if (aRun->GetFlags() & TEXT_DISABLE_OPTIONAL_LIGATURES) {
|
||||
|
@ -1404,18 +1585,15 @@ gfxAtsuiFontGroup::InitTextRun(gfxTextRun *aRun,
|
|||
|
||||
static ATSUAttributeTag layoutTags[] = {
|
||||
kATSULineLayoutOptionsTag,
|
||||
kATSULineFontFallbacksTag,
|
||||
kATSULayoutOperationOverrideTag
|
||||
};
|
||||
static ByteCount layoutArgSizes[] = {
|
||||
sizeof(ATSLineLayoutOptions),
|
||||
sizeof(ATSUFontFallbacks),
|
||||
sizeof(ATSULayoutOperationOverrideSpecifier)
|
||||
};
|
||||
|
||||
ATSUAttributeValuePtr layoutArgs[] = {
|
||||
&lineLayoutOptions,
|
||||
GetATSUFontFallbacksPtr(),
|
||||
&override
|
||||
};
|
||||
ATSUSetLayoutControls(layout,
|
||||
|
@ -1427,230 +1605,75 @@ gfxAtsuiFontGroup::InitTextRun(gfxTextRun *aRun,
|
|||
/* Now go through and update the styles for the text, based on font matching. */
|
||||
|
||||
nsAutoArrayPtr<PRUnichar> mirroredStr;
|
||||
nsTArray<PRUint32> missingOffsetsAndLengths;
|
||||
nsTArray<ATSUFontFallbacks> fallbacksToDispose;
|
||||
|
||||
PRBool firstTime = PR_TRUE;
|
||||
|
||||
UniCharArrayOffset runStart = headerChars;
|
||||
UniCharCount runLength = aSegmentLength;
|
||||
UniCharCount totalLength = headerChars + aSegmentLength;
|
||||
|
||||
nsresult rv;
|
||||
/// ---- match fonts using cmap info instead of ATSUI ----
|
||||
|
||||
CmapFontMatcher fontMatcher(aString, runStart, runStart + runLength, this);
|
||||
|
||||
while (runStart < totalLength) {
|
||||
gfxAtsuiFont *matchedFont;
|
||||
UniCharCount matchedLength;
|
||||
|
||||
// match a range of text
|
||||
matchedLength = fontMatcher.MatchNextRange();
|
||||
matchedFont = fontMatcher.MatchedFont();
|
||||
|
||||
//fprintf (stderr, "==== Starting font maching [string length: %d (%s)]\n", totalLength, NS_ConvertUTF16toUTF8(aString, aLength).get());
|
||||
do {
|
||||
PRUint32 missingRanges = missingOffsetsAndLengths.Length() / 2;
|
||||
UniCharArrayOffset missingStart = 0;
|
||||
UniCharCount missingLength = 0;
|
||||
#ifdef DUMP_TEXT_RUNS
|
||||
PR_LOG(gAtsuiTextRunLog, PR_LOG_DEBUG, ("InitTextRun %p fontgroup %p font %p match %s (%d-%d)", aRun, this, matchedFont, (matchedFont ? NS_ConvertUTF16toUTF8(matchedFont->GetUniqueName()).get() : "<null>"), runStart, matchedLength));
|
||||
#endif
|
||||
//printf("Matched: %s [%d, %d)\n", (matchedFont ? NS_ConvertUTF16toUTF8(matchedFont->GetUniqueName()).get() : "<null>"), runStart, runStart + matchedLength);
|
||||
|
||||
// in the RTL case, handle fallback mirroring
|
||||
if (aRun->IsRightToLeft() && matchedFont && !matchedFont->HasMirroringInfo()) {
|
||||
MirrorSubstring(layout, mirroredStr, aString, aLength, runStart, runLength);
|
||||
}
|
||||
|
||||
//fprintf (stderr, "(loop start, missing ranges: %d)\n", missingRanges);
|
||||
|
||||
if (missingRanges > 0) {
|
||||
// we had some misses. Let's figure out what languages we need
|
||||
// and pull in the fallback fonts from prefs.
|
||||
|
||||
missingStart = missingOffsetsAndLengths[(missingRanges-1) * 2];
|
||||
missingLength = missingOffsetsAndLengths[(missingRanges-1) * 2 + 1];
|
||||
missingOffsetsAndLengths.RemoveElementsAt((missingRanges-1) * 2, 2);
|
||||
|
||||
runStart = missingStart;
|
||||
runLength = missingLength;
|
||||
|
||||
//fprintf (stderr, ".. range: %d %d\n", runStart, runLength);
|
||||
|
||||
totalLength = runStart + runLength;
|
||||
|
||||
PRUint32 didAppendFonts = 0;
|
||||
PRUint32 lastRange = kRangeTableBase;
|
||||
|
||||
nsAutoTArray<nsRefPtr<gfxFont>,3> mLangFonts;
|
||||
|
||||
for (PRUint32 j = 0; j < runLength; j++) {
|
||||
PRUint32 unicodeRange = FindCharUnicodeRange(aString[j+runStart]);
|
||||
if (unicodeRange == lastRange)
|
||||
continue;
|
||||
|
||||
lastRange = unicodeRange;
|
||||
eFontPrefLang prefLang = GetFontPrefLangFor(unicodeRange);
|
||||
|
||||
if (prefLang == eFontPrefLang_CJKSet)
|
||||
rv = AppendCJKPrefFonts(&mLangFonts, didAppendFonts, GetStyle());
|
||||
else
|
||||
rv = AppendPrefFonts(&mLangFonts, prefLang, didAppendFonts, GetStyle());
|
||||
if (NS_FAILED(rv))
|
||||
break;
|
||||
}
|
||||
|
||||
if (NS_FAILED(rv))
|
||||
break;
|
||||
|
||||
// always append Unicode
|
||||
rv = AppendPrefFonts(&mLangFonts, eFontPrefLang_Others, didAppendFonts, GetStyle());
|
||||
if (NS_FAILED(rv))
|
||||
break;
|
||||
|
||||
// now we have a list of fonts in mLangFonts (potentially -- 0-length is ok)
|
||||
ATSUFontFallbacks langFallbacks;
|
||||
rv = CreateFontFallbacksFromFontList(&mLangFonts, &langFallbacks, kATSUSequentialFallbacksPreferred);
|
||||
if (NS_FAILED(rv))
|
||||
break;
|
||||
|
||||
fallbacksToDispose.AppendElement(langFallbacks);
|
||||
|
||||
static ATSUAttributeTag fallbackTags[] = { kATSULineFontFallbacksTag };
|
||||
static ByteCount fallbackArgSizes[] = { sizeof(ATSUFontFallbacks) };
|
||||
ATSUAttributeValuePtr fallbackArgs[] = { &langFallbacks };
|
||||
|
||||
ATSUSetLayoutControls(layout,
|
||||
NS_ARRAY_LENGTH(fallbackTags),
|
||||
fallbackTags, fallbackArgSizes, fallbackArgs);
|
||||
}
|
||||
|
||||
while (runStart < totalLength) {
|
||||
ATSUFontID substituteFontID;
|
||||
UniCharArrayOffset changedOffset;
|
||||
UniCharCount changedLength;
|
||||
UniCharCount foundCharacters;
|
||||
|
||||
OSStatus status = ATSUMatchFontsToText(layout, runStart, runLength,
|
||||
&substituteFontID, &changedOffset, &changedLength);
|
||||
|
||||
if (status == noErr) {
|
||||
foundCharacters = runLength;
|
||||
changedLength = 0;
|
||||
} else {
|
||||
foundCharacters = changedOffset - runStart;
|
||||
}
|
||||
|
||||
// first, handle any characters that were matched with firstFont
|
||||
if (foundCharacters) {
|
||||
//fprintf (stderr, "... glyphs found in first: %d %d\n", runStart, foundCharacters);
|
||||
// glyphs exist for all characters in the [runStart, runStart + foundCharacters) substring
|
||||
|
||||
// in the RTL case, handle fallback mirroring
|
||||
if (aRun->IsRightToLeft() && !firstFont->HasMirroringInfo()) {
|
||||
MirrorSubstring(layout, mirroredStr, aString, aLength, runStart, runLength);
|
||||
}
|
||||
// if no matched font, mark as unmatched
|
||||
if (!matchedFont) {
|
||||
|
||||
aRun->AddGlyphRun(firstFont, aSegmentStart + runStart - headerChars, PR_TRUE);
|
||||
|
||||
// add a glyph run for the entire substring
|
||||
aRun->AddGlyphRun(firstFont, aSegmentStart + runStart - headerChars, PR_TRUE);
|
||||
|
||||
// do we have any more work to do?
|
||||
if (status == noErr)
|
||||
break;
|
||||
}
|
||||
|
||||
if (firstTime && !HasFont(substituteFontID)) {
|
||||
// XXX We are using kATSUSequentialFallbacksExclusive at first time.
|
||||
// But the method uses non-listed font in font fallbacks on 10.4. (ATSUI Reference does not say so...)
|
||||
status = kATSUFontsNotMatched;
|
||||
}
|
||||
|
||||
// then, handle any chars that were found in the fallback list
|
||||
if (status == kATSUFontsMatched) {
|
||||
// substitute font will be used in [changedOffset, changedOffset + changedLength)
|
||||
gfxAtsuiFont *font = FindFontFor(substituteFontID);
|
||||
|
||||
//fprintf (stderr, "... glyphs matched in fallback: %d %d (%s)\n", changedOffset, changedLength, NS_ConvertUTF16toUTF8(font->GetUniqueName()).get());
|
||||
|
||||
if (font) {
|
||||
// create a new style for the substitute font
|
||||
ATSUStyle subStyle;
|
||||
ATSUCreateStyle (&subStyle);
|
||||
ATSUCopyAttributes (mainStyle, subStyle);
|
||||
|
||||
ATSUAttributeTag fontTags[] = { kATSUFontTag };
|
||||
ByteCount fontArgSizes[] = { sizeof(ATSUFontID) };
|
||||
ATSUAttributeValuePtr fontArgs[] = { &substituteFontID };
|
||||
|
||||
ATSUSetAttributes (subStyle, 1, fontTags, fontArgSizes, fontArgs);
|
||||
|
||||
// apply the new style to the layout for the changed substring
|
||||
ATSUSetRunStyle (layout, subStyle, changedOffset, changedLength);
|
||||
|
||||
stylesToDispose.AppendElement(subStyle);
|
||||
|
||||
// add a glyph run for [changedOffset, changedOffset + changedLength) with the
|
||||
// substituted font
|
||||
|
||||
// in the RTL case, handle fallback mirroring
|
||||
if (aRun->IsRightToLeft() && !font->HasMirroringInfo()) {
|
||||
MirrorSubstring(layout, mirroredStr, aString, aLength, changedOffset,
|
||||
changedLength);
|
||||
}
|
||||
|
||||
aRun->AddGlyphRun(font, aSegmentStart + changedOffset - headerChars, PR_TRUE);
|
||||
} else {
|
||||
// We could hit this case if we decided to ignore the
|
||||
// font when enumerating at startup; pretend that these are
|
||||
// missing glyphs.
|
||||
// XXX - wait, why did it even end up in the fallback list,
|
||||
// then?
|
||||
|
||||
status = kATSUFontsNotMatched;
|
||||
if (!closure.mUnmatchedChars) {
|
||||
closure.mUnmatchedChars = new PRPackedBool[aLength];
|
||||
if (closure.mUnmatchedChars) {
|
||||
//printf("initializing %d\n", aLength);
|
||||
memset(closure.mUnmatchedChars.get(), PR_FALSE, aLength);
|
||||
}
|
||||
}
|
||||
|
||||
if (status == kATSUFontsNotMatched) {
|
||||
//fprintf (stderr, "... glyphs not found: %d %d\n", changedOffset, changedLength);
|
||||
|
||||
// If this is our first time through (no fallback),
|
||||
// or if we're missing a different range than before,
|
||||
// add it to the list of ranges to examine
|
||||
if (firstTime ||
|
||||
(changedOffset != missingStart && changedLength != missingLength))
|
||||
{
|
||||
//fprintf (stderr, " (will look again at %d %d)\n", changedOffset, changedLength);
|
||||
missingOffsetsAndLengths.AppendElement(changedOffset);
|
||||
missingOffsetsAndLengths.AppendElement(changedLength);
|
||||
} else {
|
||||
aRun->AddGlyphRun(firstFont, aSegmentStart + changedOffset - headerChars, PR_TRUE);
|
||||
|
||||
if (!closure.mUnmatchedChars) {
|
||||
closure.mUnmatchedChars = new PRPackedBool[aLength];
|
||||
if (closure.mUnmatchedChars) {
|
||||
memset(closure.mUnmatchedChars.get(), PR_FALSE, aLength);
|
||||
}
|
||||
}
|
||||
|
||||
if (closure.mUnmatchedChars) {
|
||||
memset(closure.mUnmatchedChars.get() + changedOffset - headerChars,
|
||||
PR_TRUE, changedLength);
|
||||
}
|
||||
}
|
||||
|
||||
if (closure.mUnmatchedChars) {
|
||||
//printf("setting %d unmatched from %d\n", matchedLength, runStart - headerChars);
|
||||
memset(closure.mUnmatchedChars.get() + runStart - headerChars,
|
||||
PR_TRUE, matchedLength);
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
if (matchedFont != firstFont) {
|
||||
// create a new sub-style and add it to the layout
|
||||
ATSUStyle subStyle = SetLayoutRangeToFont(layout, mainStyle, runStart, matchedLength, matchedFont->GetATSUFontID());
|
||||
stylesToDispose.AppendElement(subStyle);
|
||||
}
|
||||
|
||||
//fprintf (stderr, "total length: %d changedOffset: %d changedLength: %d\n", runLength, changedOffset, changedLength);
|
||||
|
||||
runStart = changedOffset + changedLength;
|
||||
runLength = totalLength - runStart;
|
||||
// add a glyph run for the matched substring
|
||||
aRun->AddGlyphRun(matchedFont, aSegmentStart + runStart - headerChars, PR_TRUE);
|
||||
}
|
||||
|
||||
firstTime = PR_FALSE;
|
||||
} while (missingOffsetsAndLengths.Length() > 0);
|
||||
|
||||
// put back the fallback object, because we'll be disposing
|
||||
// of any of the ones we created while doing fallback
|
||||
if (fallbacksToDispose.Length() > 0) {
|
||||
static ATSUAttributeTag fallbackTags[] = { kATSULineFontFallbacksTag };
|
||||
static ByteCount fallbackArgSizes[] = { sizeof(ATSUFontFallbacks) };
|
||||
ATSUAttributeValuePtr fallbackArgs[] = { GetATSUFontFallbacksPtr() };
|
||||
|
||||
ATSUSetLayoutControls(layout,
|
||||
NS_ARRAY_LENGTH(fallbackTags),
|
||||
fallbackTags, fallbackArgSizes, fallbackArgs);
|
||||
|
||||
runStart += matchedLength;
|
||||
runLength -= matchedLength;
|
||||
}
|
||||
|
||||
|
||||
for (PRUint32 i = 0; i < fallbacksToDispose.Length(); i++)
|
||||
ATSUDisposeFontFallbacks(fallbacksToDispose[i]);
|
||||
/// -------------------------------------------------
|
||||
|
||||
// sort our glyph runs; we may have added
|
||||
// some out of order while doing fallback font matching
|
||||
// xxx - for some reason, this call appears to be needed to avoid assertions about glyph runs not being coalesced properly
|
||||
// this appears to occur when there are unmatched characters in the text run
|
||||
aRun->SortGlyphRuns();
|
||||
|
||||
//fprintf (stderr, "==== End font matching\n");
|
||||
|
||||
// Trigger layout so that our callback fires. We don't actually care about
|
||||
// the result of this call.
|
||||
ATSTrapezoid trap;
|
||||
|
|
|
@ -0,0 +1,412 @@
|
|||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is thebes gfx code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Mozilla Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2007
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Stuart Parmenter <stuart@mozilla.com>
|
||||
* John Daggett <jdaggett@mozilla.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "gfxFontUtils.h"
|
||||
|
||||
|
||||
#define NO_RANGE_FOUND 126 // bit 126 in the font unicode ranges is required to be 0
|
||||
|
||||
/* Unicode subrange table
|
||||
* from: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/intl/unicode_63ub.asp
|
||||
*
|
||||
* Use something like:
|
||||
* perl -pi -e 's/^(\d+)\s+([\dA-Fa-f]+)\s+-\s+([\dA-Fa-f]+)\s+\b(.*)/ { \1, 0x\2, 0x\3,\"\4\" },/' < unicoderanges.txt
|
||||
* to generate the below list.
|
||||
*/
|
||||
struct UnicodeRangeTableEntry
|
||||
{
|
||||
PRUint8 bit;
|
||||
PRUint32 start;
|
||||
PRUint32 end;
|
||||
const char *info;
|
||||
};
|
||||
|
||||
static const struct UnicodeRangeTableEntry gUnicodeRanges[] = {
|
||||
{ 0, 0x0000, 0x007F, "Basic Latin" },
|
||||
{ 1, 0x0080, 0x00FF, "Latin-1 Supplement" },
|
||||
{ 2, 0x0100, 0x017F, "Latin Extended-A" },
|
||||
{ 3, 0x0180, 0x024F, "Latin Extended-B" },
|
||||
{ 4, 0x0250, 0x02AF, "IPA Extensions" },
|
||||
{ 4, 0x1D00, 0x1D7F, "Phonetic Extensions" },
|
||||
{ 4, 0x1D80, 0x1DBF, "Phonetic Extensions Supplement" },
|
||||
{ 5, 0x02B0, 0x02FF, "Spacing Modifier Letters" },
|
||||
{ 5, 0xA700, 0xA71F, "Modifier Tone Letters" },
|
||||
{ 6, 0x0300, 0x036F, "Spacing Modifier Letters" },
|
||||
{ 6, 0x1DC0, 0x1DFF, "Combining Diacritical Marks Supplement" },
|
||||
{ 7, 0x0370, 0x03FF, "Greek and Coptic" },
|
||||
{ 8, 0x2C80, 0x2CFF, "Coptic" },
|
||||
{ 9, 0x0400, 0x04FF, "Cyrillic" },
|
||||
{ 9, 0x0500, 0x052F, "Cyrillic Supplementary" },
|
||||
{ 10, 0x0530, 0x058F, "Armenian" },
|
||||
{ 11, 0x0590, 0x05FF, "Basic Hebrew" },
|
||||
/* 12 - reserved */
|
||||
{ 13, 0x0600, 0x06FF, "Basic Arabic" },
|
||||
{ 13, 0x0750, 0x077F, "Arabic Supplement" },
|
||||
{ 14, 0x07C0, 0x07FF, "N'Ko" },
|
||||
{ 15, 0x0900, 0x097F, "Devanagari" },
|
||||
{ 16, 0x0980, 0x09FF, "Bengali" },
|
||||
{ 17, 0x0A00, 0x0A7F, "Gurmukhi" },
|
||||
{ 18, 0x0A80, 0x0AFF, "Gujarati" },
|
||||
{ 19, 0x0B00, 0x0B7F, "Oriya" },
|
||||
{ 20, 0x0B80, 0x0BFF, "Tamil" },
|
||||
{ 21, 0x0C00, 0x0C7F, "Telugu" },
|
||||
{ 22, 0x0C80, 0x0CFF, "Kannada" },
|
||||
{ 23, 0x0D00, 0x0D7F, "Malayalam" },
|
||||
{ 24, 0x0E00, 0x0E7F, "Thai" },
|
||||
{ 25, 0x0E80, 0x0EFF, "Lao" },
|
||||
{ 26, 0x10A0, 0x10FF, "Georgian" },
|
||||
{ 26, 0x2D00, 0x2D2F, "Georgian Supplement" },
|
||||
{ 27, 0x1B00, 0x1B7F, "Balinese" },
|
||||
{ 28, 0x1100, 0x11FF, "Hangul Jamo" },
|
||||
{ 29, 0x1E00, 0x1EFF, "Latin Extended Additional" },
|
||||
{ 29, 0x2C60, 0x2C7F, "Latin Extended-C" },
|
||||
{ 30, 0x1F00, 0x1FFF, "Greek Extended" },
|
||||
{ 31, 0x2000, 0x206F, "General Punctuation" },
|
||||
{ 31, 0x2E00, 0x2E7F, "Supplemental Punctuation" },
|
||||
{ 32, 0x2070, 0x209F, "Subscripts and Superscripts" },
|
||||
{ 33, 0x20A0, 0x20CF, "Currency Symbols" },
|
||||
{ 34, 0x20D0, 0x20FF, "Combining Diacritical Marks for Symbols" },
|
||||
{ 35, 0x2100, 0x214F, "Letter-like Symbols" },
|
||||
{ 36, 0x2150, 0x218F, "Number Forms" },
|
||||
{ 37, 0x2190, 0x21FF, "Arrows" },
|
||||
{ 37, 0x27F0, 0x27FF, "Supplemental Arrows-A" },
|
||||
{ 37, 0x2900, 0x297F, "Supplemental Arrows-B" },
|
||||
{ 37, 0x2B00, 0x2BFF, "Miscellaneous Symbols and Arrows" },
|
||||
{ 38, 0x2200, 0x22FF, "Mathematical Operators" },
|
||||
{ 38, 0x27C0, 0x27EF, "Miscellaneous Mathematical Symbols-A" },
|
||||
{ 38, 0x2980, 0x29FF, "Miscellaneous Mathematical Symbols-B" },
|
||||
{ 38, 0x2A00, 0x2AFF, "Supplemental Mathematical Operators" },
|
||||
{ 39, 0x2300, 0x23FF, "Miscellaneous Technical" },
|
||||
{ 40, 0x2400, 0x243F, "Control Pictures" },
|
||||
{ 41, 0x2440, 0x245F, "Optical Character Recognition" },
|
||||
{ 42, 0x2460, 0x24FF, "Enclosed Alphanumerics" },
|
||||
{ 43, 0x2500, 0x257F, "Box Drawing" },
|
||||
{ 44, 0x2580, 0x259F, "Block Elements" },
|
||||
{ 45, 0x25A0, 0x25FF, "Geometric Shapes" },
|
||||
{ 46, 0x2600, 0x26FF, "Miscellaneous Symbols" },
|
||||
{ 47, 0x2700, 0x27BF, "Dingbats" },
|
||||
{ 48, 0x3000, 0x303F, "Chinese, Japanese, and Korean (CJK) Symbols and Punctuation" },
|
||||
{ 49, 0x3040, 0x309F, "Hiragana" },
|
||||
{ 50, 0x30A0, 0x30FF, "Katakana" },
|
||||
{ 50, 0x31F0, 0x31FF, "Katakana Phonetic Extensions" },
|
||||
{ 51, 0x3100, 0x312F, "Bopomofo" },
|
||||
{ 51, 0x31A0, 0x31BF, "Extended Bopomofo" },
|
||||
{ 52, 0x3130, 0x318F, "Hangul Compatibility Jamo" },
|
||||
{ 53, 0xA840, 0xA87F, "Phags-pa" },
|
||||
{ 54, 0x3200, 0x32FF, "Enclosed CJK Letters and Months" },
|
||||
{ 55, 0x3300, 0x33FF, "CJK Compatibility" },
|
||||
{ 56, 0xAC00, 0xD7A3, "Hangul" },
|
||||
{ 57, 0xD800, 0xDFFF, "Surrogates. Note that setting this bit implies that there is at least one supplementary code point beyond the Basic Multilingual Plane (BMP) that is supported by this font. See Surrogates and Supplementary Characters." },
|
||||
{ 58, 0x10900, 0x1091F, "Phoenician" },
|
||||
{ 59, 0x2E80, 0x2EFF, "CJK Radicals Supplement" },
|
||||
{ 59, 0x2F00, 0x2FDF, "Kangxi Radicals" },
|
||||
{ 59, 0x2FF0, 0x2FFF, "Ideographic Description Characters" },
|
||||
{ 59, 0x3190, 0x319F, "Kanbun" },
|
||||
{ 59, 0x3400, 0x4DBF, "CJK Unified Ideographs Extension A" },
|
||||
{ 59, 0x4E00, 0x9FFF, "CJK Unified Ideographs" },
|
||||
{ 59, 0x20000, 0x2A6DF, "CJK Unified Ideographs Extension B" },
|
||||
{ 60, 0xE000, 0xF8FF, "Private Use (Plane 0)" },
|
||||
{ 61, 0x31C0, 0x31EF, "CJK Base Strokes" },
|
||||
{ 61, 0xF900, 0xFAFF, "CJK Compatibility Ideographs" },
|
||||
{ 61, 0x2F800, 0x2FA1F, "CJK Compatibility Ideographs Supplement" },
|
||||
{ 62, 0xFB00, 0xFB4F, "Alphabetical Presentation Forms" },
|
||||
{ 63, 0xFB50, 0xFDFF, "Arabic Presentation Forms-A" },
|
||||
{ 64, 0xFE20, 0xFE2F, "Combining Half Marks" },
|
||||
{ 65, 0xFE10, 0xFE1F, "Vertical Forms" },
|
||||
{ 65, 0xFE30, 0xFE4F, "CJK Compatibility Forms" },
|
||||
{ 66, 0xFE50, 0xFE6F, "Small Form Variants" },
|
||||
{ 67, 0xFE70, 0xFEFE, "Arabic Presentation Forms-B" },
|
||||
{ 68, 0xFF00, 0xFFEF, "Halfwidth and Fullwidth Forms" },
|
||||
{ 69, 0xFFF0, 0xFFFF, "Specials" },
|
||||
{ 70, 0x0F00, 0x0FFF, "Tibetan" },
|
||||
{ 71, 0x0700, 0x074F, "Syriac" },
|
||||
{ 72, 0x0780, 0x07BF, "Thaana" },
|
||||
{ 73, 0x0D80, 0x0DFF, "Sinhala" },
|
||||
{ 74, 0x1000, 0x109F, "Myanmar" },
|
||||
{ 75, 0x1200, 0x137F, "Ethiopic" },
|
||||
{ 75, 0x1380, 0x139F, "Ethiopic Supplement" },
|
||||
{ 75, 0x2D80, 0x2DDF, "Ethiopic Extended" },
|
||||
{ 76, 0x13A0, 0x13FF, "Cherokee" },
|
||||
{ 77, 0x1400, 0x167F, "Canadian Aboriginal Syllabics" },
|
||||
{ 78, 0x1680, 0x169F, "Ogham" },
|
||||
{ 79, 0x16A0, 0x16FF, "Runic" },
|
||||
{ 80, 0x1780, 0x17FF, "Khmer" },
|
||||
{ 80, 0x19E0, 0x19FF, "Khmer Symbols" },
|
||||
{ 81, 0x1800, 0x18AF, "Mongolian" },
|
||||
{ 82, 0x2800, 0x28FF, "Braille" },
|
||||
{ 83, 0xA000, 0xA48F, "Yi" },
|
||||
{ 83, 0xA490, 0xA4CF, "Yi Radicals" },
|
||||
{ 84, 0x1700, 0x171F, "Tagalog" },
|
||||
{ 84, 0x1720, 0x173F, "Hanunoo" },
|
||||
{ 84, 0x1740, 0x175F, "Buhid" },
|
||||
{ 84, 0x1760, 0x177F, "Tagbanwa" },
|
||||
{ 85, 0x10300, 0x1032F, "Old Italic" },
|
||||
{ 86, 0x10330, 0x1034F, "Gothic" },
|
||||
{ 87, 0x10440, 0x1044F, "Deseret" },
|
||||
{ 88, 0x1D000, 0x1D0FF, "Byzantine Musical Symbols" },
|
||||
{ 88, 0x1D100, 0x1D1FF, "Musical Symbols" },
|
||||
{ 88, 0x1D200, 0x1D24F, "Ancient Greek Musical Notation" },
|
||||
{ 89, 0x1D400, 0x1D7FF, "Mathematical Alphanumeric Symbols" },
|
||||
{ 90, 0xFF000, 0xFFFFD, "Private Use (Plane 15)" },
|
||||
{ 90, 0x100000, 0x10FFFD, "Private Use (Plane 16)" },
|
||||
{ 91, 0xFE00, 0xFE0F, "Variation Selectors" },
|
||||
{ 91, 0xE0100, 0xE01EF, "Variation Selectors Supplement" },
|
||||
{ 92, 0xE0000, 0xE007F, "Tags" },
|
||||
{ 93, 0x1900, 0x194F, "Limbu" },
|
||||
{ 94, 0x1950, 0x197F, "Tai Le" },
|
||||
{ 95, 0x1980, 0x19DF, "New Tai Lue" },
|
||||
{ 96, 0x1A00, 0x1A1F, "Buginese" },
|
||||
{ 97, 0x2C00, 0x2C5F, "Glagolitic" },
|
||||
{ 98, 0x2D40, 0x2D7F, "Tifinagh" },
|
||||
{ 99, 0x4DC0, 0x4DFF, "Yijing Hexagram Symbols" },
|
||||
{ 100, 0xA800, 0xA82F, "Syloti Nagri" },
|
||||
{ 101, 0x10000, 0x1007F, "Linear B Syllabary" },
|
||||
{ 101, 0x10080, 0x100FF, "Linear B Ideograms" },
|
||||
{ 101, 0x10100, 0x1013F, "Aegean Numbers" },
|
||||
{ 102, 0x10140, 0x1018F, "Ancient Greek Numbers" },
|
||||
{ 103, 0x10380, 0x1039F, "Ugaritic" },
|
||||
{ 104, 0x103A0, 0x103DF, "Old Persian" },
|
||||
{ 105, 0x10450, 0x1047F, "Shavian" },
|
||||
{ 106, 0x10480, 0x104AF, "Osmanya" },
|
||||
{ 107, 0x10800, 0x1083F, "Cypriot Syllabary" },
|
||||
{ 108, 0x10A00, 0x10A5F, "Kharoshthi" },
|
||||
{ 109, 0x1D300, 0x1D35F, "Tai Xuan Jing Symbols" },
|
||||
{ 110, 0x12000, 0x123FF, "Cuneiform" },
|
||||
{ 110, 0x12400, 0x1247F, "Cuneiform Numbers and Punctuation" },
|
||||
{ 111, 0x1D360, 0x1D37F, "Counting Rod Numerals" }
|
||||
};
|
||||
|
||||
|
||||
nsresult
|
||||
gfxFontUtils::ReadCMAPTableFormat12(PRUint8 *aBuf, PRInt32 aLength, gfxSparseBitSet& aCharacterMap, std::bitset<128>& aUnicodeRanges)
|
||||
{
|
||||
enum {
|
||||
OffsetFormat = 0,
|
||||
OffsetReserved = 2,
|
||||
OffsetTableLength = 4,
|
||||
OffsetLanguage = 8,
|
||||
OffsetNumberGroups = 12,
|
||||
OffsetGroups = 16,
|
||||
|
||||
SizeOfGroup = 12,
|
||||
|
||||
GroupOffsetStartCode = 0,
|
||||
GroupOffsetEndCode = 4
|
||||
};
|
||||
NS_ENSURE_TRUE(aLength >= 16, NS_ERROR_FAILURE);
|
||||
|
||||
NS_ENSURE_TRUE(ReadShortAt(aBuf, OffsetFormat) == 12, NS_ERROR_FAILURE);
|
||||
NS_ENSURE_TRUE(ReadShortAt(aBuf, OffsetReserved) == 0, NS_ERROR_FAILURE);
|
||||
|
||||
PRUint32 tablelen = ReadLongAt(aBuf, OffsetTableLength);
|
||||
NS_ENSURE_TRUE(tablelen <= aLength, NS_ERROR_FAILURE);
|
||||
NS_ENSURE_TRUE(tablelen >= 16, NS_ERROR_FAILURE);
|
||||
|
||||
NS_ENSURE_TRUE(ReadLongAt(aBuf, OffsetLanguage) == 0, NS_ERROR_FAILURE);
|
||||
|
||||
const PRUint32 numGroups = ReadLongAt(aBuf, OffsetNumberGroups);
|
||||
NS_ENSURE_TRUE(tablelen >= 16 + (12 * numGroups), NS_ERROR_FAILURE);
|
||||
|
||||
const PRUint8 *groups = aBuf + OffsetGroups;
|
||||
for (PRUint32 i = 0; i < numGroups; i++, groups += SizeOfGroup) {
|
||||
const PRUint32 startCharCode = ReadLongAt(groups, GroupOffsetStartCode);
|
||||
const PRUint32 endCharCode = ReadLongAt(groups, GroupOffsetEndCode);
|
||||
aCharacterMap.SetRange(startCharCode, endCharCode);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
gfxFontUtils::ReadCMAPTableFormat4(PRUint8 *aBuf, PRInt32 aLength, gfxSparseBitSet& aCharacterMap, std::bitset<128>& aUnicodeRanges)
|
||||
{
|
||||
enum {
|
||||
OffsetFormat = 0,
|
||||
OffsetLength = 2,
|
||||
OffsetLanguage = 4,
|
||||
OffsetSegCountX2 = 6
|
||||
};
|
||||
|
||||
NS_ENSURE_TRUE(ReadShortAt(aBuf, OffsetFormat) == 4, NS_ERROR_FAILURE);
|
||||
PRUint16 tablelen = ReadShortAt(aBuf, OffsetLength);
|
||||
NS_ENSURE_TRUE(tablelen <= aLength, NS_ERROR_FAILURE);
|
||||
NS_ENSURE_TRUE(tablelen > 16, NS_ERROR_FAILURE);
|
||||
|
||||
// some buggy fonts on Mac OS report lang = English (e.g. Arial Narrow Bold, v. 1.1 (Tiger))
|
||||
#if defined(XP_WIN)
|
||||
NS_ENSURE_TRUE(ReadShortAt(aBuf, OffsetLanguage) == 0, NS_ERROR_FAILURE);
|
||||
#endif
|
||||
|
||||
PRUint16 segCountX2 = ReadShortAt(aBuf, OffsetSegCountX2);
|
||||
NS_ENSURE_TRUE(tablelen >= 16 + (segCountX2 * 4), NS_ERROR_FAILURE);
|
||||
|
||||
const PRUint16 segCount = segCountX2 / 2;
|
||||
|
||||
const PRUint16 *endCounts = (PRUint16*)(aBuf + 14);
|
||||
const PRUint16 *startCounts = endCounts + 1 /* skip one uint16 for reservedPad */ + segCount;
|
||||
const PRUint16 *idDeltas = startCounts + segCount;
|
||||
const PRUint16 *idRangeOffsets = idDeltas + segCount;
|
||||
for (PRUint16 i = 0; i < segCount; i++) {
|
||||
const PRUint16 endCount = ReadShortAt16(endCounts, i);
|
||||
const PRUint16 startCount = ReadShortAt16(startCounts, i);
|
||||
const PRUint16 idRangeOffset = ReadShortAt16(idRangeOffsets, i);
|
||||
if (idRangeOffset == 0) {
|
||||
aCharacterMap.SetRange(startCount, endCount);
|
||||
} else {
|
||||
const PRUint16 idDelta = ReadShortAt16(idDeltas, i);
|
||||
for (PRUint32 c = startCount; c <= endCount; ++c) {
|
||||
if (c == 0xFFFF)
|
||||
break;
|
||||
|
||||
const PRUint16 *gdata = (idRangeOffset/2
|
||||
+ (c - startCount)
|
||||
+ &idRangeOffsets[i]);
|
||||
|
||||
NS_ENSURE_TRUE((PRUint8*)gdata > aBuf && (PRUint8*)gdata < aBuf + aLength, NS_ERROR_FAILURE);
|
||||
|
||||
// make sure we have a glyph
|
||||
if (*gdata != 0) {
|
||||
// The glyph index at this point is:
|
||||
// glyph = (ReadShortAt16(idDeltas, i) + *gdata) % 65536;
|
||||
|
||||
aCharacterMap.set(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Windows requires fonts to have a format-4 cmap with a Microsoft ID (3). On the Mac, fonts either have
|
||||
// a format-4 cmap with Microsoft platform/encoding id or they have one with a platformID == Unicode (0)
|
||||
// For fonts with two format-4 tables, the first one (Unicode platform) is preferred on the Mac.
|
||||
|
||||
#if defined(XP_MACOSX)
|
||||
#define acceptablePlatform(p) ((p) == PlatformIDUnicode || (p) == PlatformIDMicrosoft)
|
||||
#define acceptableFormat4(p,e,k) ( ((p) == PlatformIDMicrosoft && (e) == EncodingIDMicrosoft && (k) != 4) || \
|
||||
((p) == PlatformIDUnicode) )
|
||||
#define isSymbol(p,e) ((p) == PlatformIDMicrosoft && (e) == EncodingIDSymbol)
|
||||
#else
|
||||
#define acceptablePlatform(p) ((p) == PlatformIDMicrosoft)
|
||||
#define acceptableFormat4(p,e,k) ((e) == EncodingIDMicrosoft)
|
||||
#define isSymbol(p,e) ((e) == EncodingIDSymbol)
|
||||
#endif
|
||||
|
||||
nsresult
|
||||
gfxFontUtils::ReadCMAP(PRUint8 *aBuf, PRUint32 aBufLength, gfxSparseBitSet& aCharacterMap, std::bitset<128>& aUnicodeRanges,
|
||||
PRPackedBool& aUnicodeFont, PRPackedBool& aSymbolFont)
|
||||
{
|
||||
enum {
|
||||
OffsetVersion = 0,
|
||||
OffsetNumTables = 2,
|
||||
SizeOfHeader = 4,
|
||||
|
||||
TableOffsetPlatformID = 0,
|
||||
TableOffsetEncodingID = 2,
|
||||
TableOffsetOffset = 4,
|
||||
SizeOfTable = 8,
|
||||
|
||||
SubtableOffsetFormat = 0
|
||||
};
|
||||
enum {
|
||||
PlatformIDUnicode = 0,
|
||||
PlatformIDMicrosoft = 3
|
||||
};
|
||||
enum {
|
||||
EncodingIDSymbol = 0,
|
||||
EncodingIDMicrosoft = 1,
|
||||
EncodingIDUCS4 = 10
|
||||
};
|
||||
|
||||
PRUint16 version = ReadShortAt(aBuf, OffsetVersion);
|
||||
PRUint16 numTables = ReadShortAt(aBuf, OffsetNumTables);
|
||||
|
||||
// save the format and offset we want here
|
||||
PRUint32 keepOffset = 0;
|
||||
PRUint32 keepFormat = 0;
|
||||
|
||||
PRUint8 *table = aBuf + SizeOfHeader;
|
||||
for (PRUint16 i = 0; i < numTables; ++i, table += SizeOfTable) {
|
||||
const PRUint16 platformID = ReadShortAt(table, TableOffsetPlatformID);
|
||||
if (!acceptablePlatform(platformID))
|
||||
continue;
|
||||
|
||||
const PRUint16 encodingID = ReadShortAt(table, TableOffsetEncodingID);
|
||||
const PRUint32 offset = ReadLongAt(table, TableOffsetOffset);
|
||||
|
||||
NS_ASSERTION(offset < aBufLength, "ugh");
|
||||
const PRUint8 *subtable = aBuf + offset;
|
||||
const PRUint16 format = ReadShortAt(subtable, SubtableOffsetFormat);
|
||||
|
||||
if (isSymbol(platformID, encodingID)) {
|
||||
aUnicodeFont = PR_FALSE;
|
||||
aSymbolFont = PR_TRUE;
|
||||
keepFormat = format;
|
||||
keepOffset = offset;
|
||||
break;
|
||||
} else if (format == 4 && acceptableFormat4(platformID, encodingID, keepFormat)) {
|
||||
keepFormat = format;
|
||||
keepOffset = offset;
|
||||
} else if (format == 12 && encodingID == EncodingIDUCS4) {
|
||||
keepFormat = format;
|
||||
keepOffset = offset;
|
||||
break; // we don't want to try anything else when this format is available.
|
||||
}
|
||||
}
|
||||
|
||||
nsresult rv = NS_ERROR_FAILURE;
|
||||
|
||||
if (keepFormat == 12)
|
||||
rv = ReadCMAPTableFormat12(aBuf + keepOffset, aBufLength - keepOffset, aCharacterMap, aUnicodeRanges);
|
||||
else if (keepFormat == 4)
|
||||
rv = ReadCMAPTableFormat4(aBuf + keepOffset, aBufLength - keepOffset, aCharacterMap, aUnicodeRanges);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
PRUint8 gfxFontUtils::CharRangeBit(PRUint32 ch) {
|
||||
const PRUint32 n = sizeof(gUnicodeRanges) / sizeof(struct UnicodeRangeTableEntry);
|
||||
|
||||
for (PRUint32 i = 0; i < n; ++i)
|
||||
if (ch >= gUnicodeRanges[i].start && ch <= gUnicodeRanges[i].end)
|
||||
return gUnicodeRanges[i].bit;
|
||||
|
||||
return NO_RANGE_FOUND;
|
||||
}
|
||||
|
|
@ -238,7 +238,7 @@ AppendGenericFontFromPref(nsString& aFonts, const char *aLangGroup, const char *
|
|||
return;
|
||||
|
||||
nsCAutoString prefName;
|
||||
nsXPIDLString value;
|
||||
nsXPIDLString nameValue, nameListValue;
|
||||
|
||||
nsXPIDLString genericName;
|
||||
if (aGenericName) {
|
||||
|
@ -254,22 +254,24 @@ AppendGenericFontFromPref(nsString& aFonts, const char *aLangGroup, const char *
|
|||
genericDotLang.AppendLiteral(".");
|
||||
genericDotLang.Append(aLangGroup);
|
||||
|
||||
// fetch font.name.xxx value
|
||||
prefName.AssignLiteral("font.name.");
|
||||
prefName.Append(genericDotLang);
|
||||
rv = prefs->CopyUnicharPref(prefName.get(), getter_Copies(value));
|
||||
rv = prefs->CopyUnicharPref(prefName.get(), getter_Copies(nameValue));
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
if (!aFonts.IsEmpty())
|
||||
aFonts.AppendLiteral(", ");
|
||||
aFonts.Append(value);
|
||||
aFonts.Append(nameValue);
|
||||
}
|
||||
|
||||
// fetch font.name-list.xxx value
|
||||
prefName.AssignLiteral("font.name-list.");
|
||||
prefName.Append(genericDotLang);
|
||||
rv = prefs->CopyUnicharPref(prefName.get(), getter_Copies(value));
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
rv = prefs->CopyUnicharPref(prefName.get(), getter_Copies(nameListValue));
|
||||
if (NS_SUCCEEDED(rv) && !nameListValue.Equals(nameValue)) {
|
||||
if (!aFonts.IsEmpty())
|
||||
aFonts.AppendLiteral(", ");
|
||||
aFonts.Append(value);
|
||||
aFonts.Append(nameListValue);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
* Contributor(s):
|
||||
* Vladimir Vukicevic <vladimir@pobox.com>
|
||||
* Masayuki Nakano <masayuki@d-toybox.com>
|
||||
* John Daggett <jdaggett@mozilla.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
|
@ -41,8 +42,11 @@
|
|||
|
||||
#include "nsDataHashtable.h"
|
||||
|
||||
#include "gfxFontUtils.h"
|
||||
#include "gfxAtsuiFonts.h"
|
||||
|
||||
#include <Carbon/Carbon.h>
|
||||
|
||||
#include "nsUnicharUtils.h"
|
||||
#include "nsVoidArray.h"
|
||||
|
||||
|
@ -71,11 +75,12 @@ class FontEntry
|
|||
public:
|
||||
THEBES_INLINE_DECL_REFCOUNTING(FontEntry)
|
||||
|
||||
FontEntry(nsString &aName) :
|
||||
mName(aName), mWeight(0)
|
||||
FontEntry(ATSUFontID aFontID, nsString &aName) :
|
||||
mName(aName), mWeight(0), mUnicodeRanges(0),
|
||||
mCmapInitialized(PR_FALSE), mATSUFontID(aFontID)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
const nsString& Name() { return mName; }
|
||||
PRInt32 Weight() {
|
||||
if (!mWeight)
|
||||
|
@ -87,15 +92,28 @@ public:
|
|||
PRBool IsBold();
|
||||
NSFont* GetNSFont(float aSize);
|
||||
|
||||
ATSUFontID GetFontID() { return mATSUFontID; }
|
||||
nsresult ReadCMAP();
|
||||
inline PRBool TestCharacterMap(PRUint32 aCh) {
|
||||
if ( !mCmapInitialized ) ReadCMAP();
|
||||
return mCharacterMap.test(aCh);
|
||||
}
|
||||
|
||||
protected:
|
||||
void RealizeWeightAndTraits();
|
||||
void GetStringForNSString(const NSString *aSrc, nsAString& aDist);
|
||||
NSString* GetNSStringForString(const nsAString& aSrc);
|
||||
|
||||
ATSUFontID mATSUFontID;
|
||||
nsString mName;
|
||||
PRInt32 mWeight;
|
||||
PRPackedBool mFixedPitch;
|
||||
PRPackedBool mItalicStyle;
|
||||
|
||||
std::bitset<128> mUnicodeRanges;
|
||||
gfxSparseBitSet mCharacterMap;
|
||||
PRPackedBool mCmapInitialized;
|
||||
|
||||
};
|
||||
|
||||
class gfxQuartzFontCache {
|
||||
|
@ -131,8 +149,14 @@ public:
|
|||
const nsString& GetPostscriptNameForFontID(ATSUFontID fid);
|
||||
|
||||
PRBool IsFixedPitch(ATSUFontID fid);
|
||||
|
||||
FontEntry* FindFontEntry(ATSUFontID aFontID);
|
||||
FontEntry* FindFontForChar(const PRUint32 aCh, gfxAtsuiFont *aPrevFont);
|
||||
|
||||
private:
|
||||
static PLDHashOperator PR_CALLBACK FindFontForCharProc(nsUint32HashKey::KeyType aKey,
|
||||
nsRefPtr<FontEntry>& aFontEntry,
|
||||
void* userArg);
|
||||
static gfxQuartzFontCache *sSharedFontCache;
|
||||
|
||||
gfxQuartzFontCache();
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
* Contributor(s):
|
||||
* Vladimir Vukicevic <vladimir@pobox.com>
|
||||
* Masayuki Nakano <masayuki@d-toybox.com>
|
||||
* John Daggett <jdaggett@mozilla.com>
|
||||
*
|
||||
* Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
|
||||
*
|
||||
|
@ -42,6 +43,7 @@
|
|||
|
||||
#include "gfxPlatformMac.h"
|
||||
#include "gfxQuartzFontCache.h"
|
||||
#include "gfxAtsuiFonts.h"
|
||||
|
||||
// _atsFontID is private; add it in our new category to NSFont
|
||||
@interface NSFont (MozillaCategory)
|
||||
|
@ -147,6 +149,36 @@ FontEntry::GetNSStringForString(const nsAString& aSrc)
|
|||
return ::GetNSStringForString(aSrc);
|
||||
}
|
||||
|
||||
nsresult
|
||||
FontEntry::ReadCMAP()
|
||||
{
|
||||
OSStatus status;
|
||||
ByteCount size;
|
||||
|
||||
if (mCmapInitialized) return NS_OK;
|
||||
|
||||
// attempt this once, if errors occur leave a blank cmap
|
||||
mCmapInitialized = PR_TRUE;
|
||||
|
||||
status = ATSFontGetTable(mATSUFontID, 'cmap', 0, 0, 0, &size);
|
||||
//printf( "cmap size: %s %d\n", NS_ConvertUTF16toUTF8(mName).get(), size );
|
||||
NS_ENSURE_TRUE(status == noErr, NS_ERROR_FAILURE);
|
||||
|
||||
nsAutoTArray<PRUint8,16384> buffer;
|
||||
if (!buffer.AppendElements(size))
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
PRUint8 *cmap = buffer.Elements();
|
||||
|
||||
status = ATSFontGetTable(mATSUFontID, 'cmap', 0, size, cmap, &size);
|
||||
NS_ENSURE_TRUE(status == noErr, NS_ERROR_FAILURE);
|
||||
|
||||
nsresult rv = NS_ERROR_FAILURE;
|
||||
PRPackedBool unicodeFont, symbolFont; // currently ignored
|
||||
rv = gfxFontUtils::ReadCMAP(cmap, size, mCharacterMap, mUnicodeRanges, unicodeFont, symbolFont);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
/* gfxQuartzFontCache */
|
||||
|
||||
gfxQuartzFontCache *gfxQuartzFontCache::sSharedFontCache = nsnull;
|
||||
|
@ -343,7 +375,7 @@ gfxQuartzFontCache::InitFontList()
|
|||
|
||||
// We should get family name from mFamilies for checking the first
|
||||
// character of the name.
|
||||
nsRefPtr<FontEntry> psFont = new FontEntry(postscriptName);
|
||||
nsRefPtr<FontEntry> psFont = new FontEntry(fontIDs[i], postscriptName);
|
||||
NSFont *font = psFont->GetNSFont(10.0);
|
||||
basicFamilyName.Truncate();
|
||||
GetStringForNSString([font familyName], basicFamilyName);
|
||||
|
@ -360,6 +392,8 @@ gfxQuartzFontCache::InitFontList()
|
|||
if (!ignoreThisFont) {
|
||||
mPostscriptFonts.Put(key, psFont);
|
||||
mFontIDTable.Put(PRUint32(fontIDs[i]), psFont);
|
||||
// for now, don't read in cmap's at startup
|
||||
//psFont->ReadCMAP();
|
||||
} else {
|
||||
mNonExistingFonts.AppendString(key);
|
||||
}
|
||||
|
@ -798,3 +832,88 @@ gfxQuartzFontCache::IsFixedPitch(ATSUFontID fid)
|
|||
|
||||
return fe->IsFixedPitch();
|
||||
}
|
||||
|
||||
FontEntry*
|
||||
gfxQuartzFontCache::FindFontEntry(ATSUFontID aFontID)
|
||||
{
|
||||
nsRefPtr<FontEntry> fe;
|
||||
|
||||
if (!mFontIDTable.Get(PRUint32(aFontID), &fe)) {
|
||||
NS_WARNING("Invalid font");
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
return fe;
|
||||
}
|
||||
|
||||
struct FontSearch {
|
||||
FontSearch(const PRUint32 aCharacter, gfxAtsuiFont *aFont) :
|
||||
ch(aCharacter), fontToMatch(aFont), matchRank(0) {
|
||||
}
|
||||
const PRUint32 ch;
|
||||
gfxAtsuiFont *fontToMatch;
|
||||
PRInt32 matchRank;
|
||||
nsRefPtr<FontEntry> bestMatch;
|
||||
};
|
||||
|
||||
FontEntry*
|
||||
gfxQuartzFontCache::FindFontForChar(const PRUint32 aCh, gfxAtsuiFont *aPrevFont)
|
||||
{
|
||||
FontSearch data(aCh, aPrevFont);
|
||||
|
||||
// find fonts that support the character
|
||||
mFontIDTable.Enumerate(gfxQuartzFontCache::FindFontForCharProc, &data);
|
||||
|
||||
return data.bestMatch;
|
||||
}
|
||||
|
||||
PLDHashOperator PR_CALLBACK
|
||||
gfxQuartzFontCache::FindFontForCharProc(nsUint32HashKey::KeyType aKey, nsRefPtr<FontEntry>& aFontEntry,
|
||||
void* userArg)
|
||||
{
|
||||
FontSearch *data = (FontSearch*)userArg;
|
||||
|
||||
PRInt32 rank = 0;
|
||||
|
||||
if (aFontEntry->TestCharacterMap(data->ch)) {
|
||||
rank += 20;
|
||||
}
|
||||
|
||||
// if we didn't match any characters don't bother wasting more time.
|
||||
if (rank == 0)
|
||||
return PL_DHASH_NEXT;
|
||||
|
||||
// omitting from original windows code -- family name, lang group, pitch
|
||||
// not available in current FontEntry implementation
|
||||
|
||||
if (data->fontToMatch) {
|
||||
const gfxFontStyle *style = data->fontToMatch->GetStyle();
|
||||
|
||||
// italics
|
||||
if (aFontEntry->IsItalicStyle() && (style->style == FONT_STYLE_ITALIC || style->style == FONT_STYLE_ITALIC)) {
|
||||
rank += 5;
|
||||
}
|
||||
|
||||
// weight
|
||||
PRInt8 baseWeight, weightDistance;
|
||||
style->ComputeWeightAndOffset(&baseWeight, &weightDistance);
|
||||
PRUint16 targetWeight = (baseWeight * 100) + (weightDistance * 100);
|
||||
if (aFontEntry->Weight() == targetWeight)
|
||||
rank += 5;
|
||||
} else {
|
||||
// if no font to match, prefer non-bold, non-italic fonts
|
||||
if (!aFontEntry->IsItalicStyle() && !aFontEntry->IsBold())
|
||||
rank += 5;
|
||||
}
|
||||
|
||||
// xxx - add whether AAT font with morphing info for specific lang groups
|
||||
|
||||
if (rank > data->matchRank
|
||||
|| (rank == data->matchRank && Compare(aFontEntry->Name(), data->bestMatch->Name()) > 0))
|
||||
{
|
||||
data->bestMatch = aFontEntry;
|
||||
data->matchRank = rank;
|
||||
}
|
||||
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
|
|
@ -58,15 +58,6 @@
|
|||
|
||||
//#define DEBUG_CMAP_SIZE 1
|
||||
|
||||
/* Define this if we want to update the unicode range bitsets based
|
||||
* on the actual characters a font supports.
|
||||
*
|
||||
* Doing this can result in very large lists of fonts being returned.
|
||||
* Not doing this can let us prioritize fonts that do have the bit set
|
||||
* as they are more likely to provide better glyphs (in theory).
|
||||
*/
|
||||
//#define UPDATE_RANGES
|
||||
|
||||
int PR_CALLBACK
|
||||
gfxWindowsPlatform::PrefChangedCallback(const char *aPrefName, void *closure)
|
||||
{
|
||||
|
@ -174,139 +165,7 @@ gfxWindowsPlatform::FontEnumProc(const ENUMLOGFONTEXW *lpelfe,
|
|||
return 1;
|
||||
}
|
||||
|
||||
static inline PRUint16
|
||||
ReadShortAt(const PRUint8 *aBuf, PRUint32 aIndex)
|
||||
{
|
||||
return (aBuf[aIndex] << 8) | aBuf[aIndex + 1];
|
||||
}
|
||||
|
||||
static inline PRUint16
|
||||
ReadShortAt16(const PRUint16 *aBuf, PRUint32 aIndex)
|
||||
{
|
||||
return (((aBuf[aIndex]&0xFF) << 8) | ((aBuf[aIndex]&0xFF00) >> 8));
|
||||
}
|
||||
|
||||
static inline PRUint32
|
||||
ReadLongAt(const PRUint8 *aBuf, PRUint32 aIndex)
|
||||
{
|
||||
return ((aBuf[aIndex] << 24) | (aBuf[aIndex + 1] << 16) | (aBuf[aIndex + 2] << 8) | (aBuf[aIndex + 3]));
|
||||
}
|
||||
|
||||
static nsresult
|
||||
ReadCMAPTableFormat12(PRUint8 *aBuf, PRInt32 aLength, FontEntry *aFontEntry)
|
||||
{
|
||||
enum {
|
||||
OffsetFormat = 0,
|
||||
OffsetReserved = 2,
|
||||
OffsetTableLength = 4,
|
||||
OffsetLanguage = 8,
|
||||
OffsetNumberGroups = 12,
|
||||
OffsetGroups = 16,
|
||||
|
||||
SizeOfGroup = 12,
|
||||
|
||||
GroupOffsetStartCode = 0,
|
||||
GroupOffsetEndCode = 4
|
||||
};
|
||||
NS_ENSURE_TRUE(aLength >= 16, NS_ERROR_FAILURE);
|
||||
|
||||
NS_ENSURE_TRUE(ReadShortAt(aBuf, OffsetFormat) == 12, NS_ERROR_FAILURE);
|
||||
NS_ENSURE_TRUE(ReadShortAt(aBuf, OffsetReserved) == 0, NS_ERROR_FAILURE);
|
||||
|
||||
PRUint32 tablelen = ReadLongAt(aBuf, OffsetTableLength);
|
||||
NS_ENSURE_TRUE(tablelen <= aLength, NS_ERROR_FAILURE);
|
||||
NS_ENSURE_TRUE(tablelen >= 16, NS_ERROR_FAILURE);
|
||||
|
||||
NS_ENSURE_TRUE(ReadLongAt(aBuf, OffsetLanguage) == 0, NS_ERROR_FAILURE);
|
||||
|
||||
const PRUint32 numGroups = ReadLongAt(aBuf, OffsetNumberGroups);
|
||||
NS_ENSURE_TRUE(tablelen >= 16 + (12 * numGroups), NS_ERROR_FAILURE);
|
||||
|
||||
const PRUint8 *groups = aBuf + OffsetGroups;
|
||||
for (PRUint32 i = 0; i < numGroups; i++, groups += SizeOfGroup) {
|
||||
const PRUint32 startCharCode = ReadLongAt(groups, GroupOffsetStartCode);
|
||||
const PRUint32 endCharCode = ReadLongAt(groups, GroupOffsetEndCode);
|
||||
aFontEntry->mCharacterMap.SetRange(startCharCode, endCharCode);
|
||||
#ifdef UPDATE_RANGES
|
||||
for (PRUint32 c = startCharCode; c <= endCharCode; ++c) {
|
||||
PRUint16 b = CharRangeBit(c);
|
||||
if (b != NO_RANGE_FOUND)
|
||||
aFontEntry->mUnicodeRanges.set(b, true);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
static nsresult
|
||||
ReadCMAPTableFormat4(PRUint8 *aBuf, PRInt32 aLength, FontEntry *aFontEntry)
|
||||
{
|
||||
enum {
|
||||
OffsetFormat = 0,
|
||||
OffsetLength = 2,
|
||||
OffsetLanguage = 4,
|
||||
OffsetSegCountX2 = 6
|
||||
};
|
||||
|
||||
NS_ENSURE_TRUE(ReadShortAt(aBuf, OffsetFormat) == 4, NS_ERROR_FAILURE);
|
||||
PRUint16 tablelen = ReadShortAt(aBuf, OffsetLength);
|
||||
NS_ENSURE_TRUE(tablelen <= aLength, NS_ERROR_FAILURE);
|
||||
NS_ENSURE_TRUE(tablelen > 16, NS_ERROR_FAILURE);
|
||||
NS_ENSURE_TRUE(ReadShortAt(aBuf, OffsetLanguage) == 0, NS_ERROR_FAILURE);
|
||||
|
||||
PRUint16 segCountX2 = ReadShortAt(aBuf, OffsetSegCountX2);
|
||||
NS_ENSURE_TRUE(tablelen >= 16 + (segCountX2 * 4), NS_ERROR_FAILURE);
|
||||
|
||||
const PRUint16 segCount = segCountX2 / 2;
|
||||
|
||||
const PRUint16 *endCounts = (PRUint16*)(aBuf + 14);
|
||||
const PRUint16 *startCounts = endCounts + 1 /* skip one uint16 for reservedPad */ + segCount;
|
||||
const PRUint16 *idDeltas = startCounts + segCount;
|
||||
const PRUint16 *idRangeOffsets = idDeltas + segCount;
|
||||
for (PRUint16 i = 0; i < segCount; i++) {
|
||||
const PRUint16 endCount = ReadShortAt16(endCounts, i);
|
||||
const PRUint16 startCount = ReadShortAt16(startCounts, i);
|
||||
const PRUint16 idRangeOffset = ReadShortAt16(idRangeOffsets, i);
|
||||
if (idRangeOffset == 0) {
|
||||
aFontEntry->mCharacterMap.SetRange(startCount, endCount);
|
||||
#ifdef UPDATE_RANGES
|
||||
for (PRUint32 c = startCount; c <= endCount; c++) {
|
||||
PRUint16 b = CharRangeBit(c);
|
||||
if (b != NO_RANGE_FOUND)
|
||||
aFontEntry->mUnicodeRanges.set(b, true);
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
const PRUint16 idDelta = ReadShortAt16(idDeltas, i);
|
||||
for (PRUint32 c = startCount; c <= endCount; ++c) {
|
||||
if (c == 0xFFFF)
|
||||
break;
|
||||
|
||||
const PRUint16 *gdata = (idRangeOffset/2
|
||||
+ (c - startCount)
|
||||
+ &idRangeOffsets[i]);
|
||||
|
||||
NS_ENSURE_TRUE((PRUint8*)gdata > aBuf && (PRUint8*)gdata < aBuf + aLength, NS_ERROR_FAILURE);
|
||||
|
||||
// make sure we have a glyph
|
||||
if (*gdata != 0) {
|
||||
// The glyph index at this point is:
|
||||
// glyph = (ReadShortAt16(idDeltas, i) + *gdata) % 65536;
|
||||
|
||||
aFontEntry->mCharacterMap.set(c);
|
||||
#ifdef UPDATE_RANGES
|
||||
PRUint16 b = CharRangeBit(c);
|
||||
if (b != NO_RANGE_FOUND)
|
||||
aFontEntry->mUnicodeRanges.set(b, true);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
// general cmap reading routines moved to gfxFontUtils.cpp
|
||||
|
||||
static nsresult
|
||||
ReadCMAP(HDC hdc, FontEntry *aFontEntry)
|
||||
|
@ -324,72 +183,9 @@ ReadCMAP(HDC hdc, FontEntry *aFontEntry)
|
|||
|
||||
DWORD newLen = GetFontData(hdc, kCMAP, 0, buf, len);
|
||||
NS_ENSURE_TRUE(newLen == len, NS_ERROR_FAILURE);
|
||||
|
||||
enum {
|
||||
OffsetVersion = 0,
|
||||
OffsetNumTables = 2,
|
||||
SizeOfHeader = 4,
|
||||
|
||||
TableOffsetPlatformID = 0,
|
||||
TableOffsetEncodingID = 2,
|
||||
TableOffsetOffset = 4,
|
||||
SizeOfTable = 8,
|
||||
|
||||
SubtableOffsetFormat = 0
|
||||
};
|
||||
enum {
|
||||
PlatformIDMicrosoft = 3
|
||||
};
|
||||
enum {
|
||||
EncodingIDSymbol = 0,
|
||||
EncodingIDMicrosoft = 1,
|
||||
EncodingIDUCS4 = 10
|
||||
};
|
||||
|
||||
PRUint16 version = ReadShortAt(buf, OffsetVersion);
|
||||
PRUint16 numTables = ReadShortAt(buf, OffsetNumTables);
|
||||
|
||||
// save the format and offset we want here
|
||||
PRUint32 keepOffset = 0;
|
||||
PRUint32 keepFormat = 0;
|
||||
|
||||
PRUint8 *table = buf + SizeOfHeader;
|
||||
for (PRUint16 i = 0; i < numTables; ++i, table += SizeOfTable) {
|
||||
const PRUint16 platformID = ReadShortAt(table, TableOffsetPlatformID);
|
||||
if (platformID != PlatformIDMicrosoft)
|
||||
continue;
|
||||
|
||||
const PRUint16 encodingID = ReadShortAt(table, TableOffsetEncodingID);
|
||||
const PRUint32 offset = ReadLongAt(table, TableOffsetOffset);
|
||||
|
||||
NS_ASSERTION(offset < newLen, "ugh");
|
||||
const PRUint8 *subtable = buf + offset;
|
||||
const PRUint16 format = ReadShortAt(subtable, SubtableOffsetFormat);
|
||||
|
||||
if (encodingID == EncodingIDSymbol) {
|
||||
aFontEntry->mUnicodeFont = PR_FALSE;
|
||||
aFontEntry->mSymbolFont = PR_TRUE;
|
||||
keepFormat = format;
|
||||
keepOffset = offset;
|
||||
break;
|
||||
} else if (format == 4 && encodingID == EncodingIDMicrosoft) {
|
||||
keepFormat = format;
|
||||
keepOffset = offset;
|
||||
} else if (format == 12 && encodingID == EncodingIDUCS4) {
|
||||
keepFormat = format;
|
||||
keepOffset = offset;
|
||||
break; // we don't want to try anything else when this format is available.
|
||||
}
|
||||
}
|
||||
|
||||
nsresult rv = NS_ERROR_FAILURE;
|
||||
|
||||
if (keepFormat == 12)
|
||||
rv = ReadCMAPTableFormat12(buf + keepOffset, len - keepOffset, aFontEntry);
|
||||
else if (keepFormat == 4)
|
||||
rv = ReadCMAPTableFormat4(buf + keepOffset, len - keepOffset, aFontEntry);
|
||||
|
||||
return rv;
|
||||
|
||||
return gfxFontUtils::ReadCMAP(buf, len, aFontEntry->mCharacterMap, aFontEntry->mUnicodeRanges,
|
||||
aFontEntry->mUnicodeFont, aFontEntry->mSymbolFont);
|
||||
}
|
||||
|
||||
PLDHashOperator PR_CALLBACK
|
||||
|
@ -700,7 +496,7 @@ gfxWindowsPlatform::FindFontForStringProc(nsStringHashKey::KeyType aKey,
|
|||
|
||||
// fonts that claim to support the range are more
|
||||
// likely to be "better fonts" than ones that don't... (in theory)
|
||||
if (aFontEntry->SupportsRange(CharRangeBit(ch)))
|
||||
if (aFontEntry->SupportsRange(gfxFontUtils::CharRangeBit(ch)))
|
||||
rank += 1;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -507,7 +507,7 @@ fails == 386310-1d.html 386310-1-ref.html
|
|||
!= 389924-1a.html about:blank
|
||||
== 390318-1a.html 390318-1-ref.html
|
||||
== 390318-1b.html 390318-1-ref.html
|
||||
random-if(MOZ_WIDGET_TOOLKIT=="gtk2") == 391045.html 391045-ref.html # windows-specific bug, appears to pass on Mac because of missing fonts, but when Linux doesn't have the fonts it shows Unicode boxes which differ
|
||||
skip-if(MOZ_WIDGET_TOOLKIT!="windows") == 391045.html 391045-ref.html # windows-specific Uniscribe bug, trailing period is matched against different fonts on Mac/Linux (see 396137)
|
||||
== 391140-1.html 391140-1-ref.html
|
||||
== 391412-1a.html 391412-1-ref.html
|
||||
== 391412-1b.html 391412-1-ref.html
|
||||
|
|
Загрузка…
Ссылка в новой задаче