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
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/
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
15 * The Original Code is Mozilla Foundation code.
17 * The Initial Developer of the Original Code is Mozilla Foundation.
18 * Portions created by the Initial Developer are Copyright (C) 2005
19 * the Initial Developer. All Rights Reserved.
22 * Stuart Parmenter <stuart@mozilla.com>
23 * John Daggett <jdaggett@mozilla.com>
25 * Alternatively, the contents of this file may be used under the terms of
26 * either the GNU General Public License Version 2 or later (the "GPL"), or
27 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 * in which case the provisions of the GPL or the LGPL are applicable instead
29 * of those above. If you wish to allow use of your version of this file only
30 * under the terms of either the GPL or the LGPL, and not to allow others to
31 * use your version of this file under the terms of the MPL, indicate your
32 * decision by deleting the provisions above and replace them with the notice
33 * and other provisions required by the GPL or the LGPL. If you do not delete
34 * the provisions above, a recipient may use your version of this file under
35 * the terms of any one of the MPL, the GPL or the LGPL.
37 * ***** END LICENSE BLOCK ***** */
39 #ifndef GFX_FONT_UTILS_H
40 #define GFX_FONT_UTILS_H
47 #include "nsDataHashtable.h"
51 #include "nsIRunnable.h"
52 #include "nsThreadUtils.h"
53 #include "nsComponentManagerUtils.h"
55 #include "nsAutoPtr.h"
57 /* Bug 341128 - w32api defines min/max which causes problems with <bitset> */
65 // code from gfxWindowsFonts.h
67 class gfxSparseBitSet
{
69 enum { BLOCK_SIZE
= 32 }; // ==> 256 codepoints per block
70 enum { BLOCK_SIZE_BITS
= BLOCK_SIZE
* 8 };
71 enum { BLOCK_INDEX_SHIFT
= 8 };
74 Block(const Block
& aBlock
) { memcpy(mBits
, aBlock
.mBits
, sizeof(mBits
)); }
75 Block(unsigned char memsetValue
= 0) { memset(mBits
, memsetValue
, BLOCK_SIZE
); }
76 PRUint8 mBits
[BLOCK_SIZE
];
81 gfxSparseBitSet(const gfxSparseBitSet
& aBitset
) {
82 PRUint32 len
= aBitset
.mBlocks
.Length();
83 mBlocks
.AppendElements(len
);
84 for (PRUint32 i
= 0; i
< len
; ++i
) {
85 Block
*block
= aBitset
.mBlocks
[i
];
87 mBlocks
[i
] = new Block(*block
);
90 PRBool
test(PRUint32 aIndex
) {
91 PRUint32 blockIndex
= aIndex
/BLOCK_SIZE_BITS
;
92 if (blockIndex
>= mBlocks
.Length())
94 Block
*block
= mBlocks
[blockIndex
];
97 return ((block
->mBits
[(aIndex
>>3) & (BLOCK_SIZE
- 1)]) & (1 << (aIndex
& 0x7))) != 0;
100 PRBool
TestRange(PRUint32 aStart
, PRUint32 aEnd
) {
101 PRUint32 startBlock
, endBlock
, blockLen
;
103 // start point is beyond the end of the block array? return false immediately
104 startBlock
= aStart
>> BLOCK_INDEX_SHIFT
;
105 blockLen
= mBlocks
.Length();
106 if (startBlock
>= blockLen
) return PR_FALSE
;
108 // check for blocks in range, if none, return false
110 PRBool hasBlocksInRange
= PR_FALSE
;
112 endBlock
= aEnd
>> BLOCK_INDEX_SHIFT
;
113 blockIndex
= startBlock
;
114 for (blockIndex
= startBlock
; blockIndex
<= endBlock
; blockIndex
++) {
115 if (blockIndex
< blockLen
&& mBlocks
[blockIndex
])
116 hasBlocksInRange
= PR_TRUE
;
118 if (!hasBlocksInRange
) return PR_FALSE
;
121 PRUint32 i
, start
, end
;
123 // first block, check bits
124 if ((block
= mBlocks
[startBlock
])) {
126 end
= PR_MIN(aEnd
, ((startBlock
+1) << BLOCK_INDEX_SHIFT
) - 1);
127 for (i
= start
; i
<= end
; i
++) {
128 if ((block
->mBits
[(i
>>3) & (BLOCK_SIZE
- 1)]) & (1 << (i
& 0x7)))
132 if (endBlock
== startBlock
) return PR_FALSE
;
134 // [2..n-1] blocks check bytes
135 for (blockIndex
= startBlock
+ 1; blockIndex
< endBlock
; blockIndex
++) {
138 if (blockIndex
>= blockLen
|| !(block
= mBlocks
[blockIndex
])) continue;
139 for (index
= 0; index
< BLOCK_SIZE
; index
++) {
140 if (block
->mBits
[index
])
145 // last block, check bits
146 if (endBlock
< blockLen
&& (block
= mBlocks
[endBlock
])) {
147 start
= endBlock
<< BLOCK_INDEX_SHIFT
;
149 for (i
= start
; i
<= end
; i
++) {
150 if ((block
->mBits
[(i
>>3) & (BLOCK_SIZE
- 1)]) & (1 << (i
& 0x7)))
158 void set(PRUint32 aIndex
) {
159 PRUint32 blockIndex
= aIndex
/BLOCK_SIZE_BITS
;
160 if (blockIndex
>= mBlocks
.Length()) {
161 nsAutoPtr
<Block
> *blocks
= mBlocks
.AppendElements(blockIndex
+ 1 - mBlocks
.Length());
162 if (NS_UNLIKELY(!blocks
)) // OOM
165 Block
*block
= mBlocks
[blockIndex
];
168 if (NS_UNLIKELY(!block
)) // OOM
170 mBlocks
[blockIndex
] = block
;
172 block
->mBits
[(aIndex
>>3) & (BLOCK_SIZE
- 1)] |= 1 << (aIndex
& 0x7);
175 void SetRange(PRUint32 aStart
, PRUint32 aEnd
) {
176 const PRUint32 startIndex
= aStart
/BLOCK_SIZE_BITS
;
177 const PRUint32 endIndex
= aEnd
/BLOCK_SIZE_BITS
;
179 if (endIndex
>= mBlocks
.Length()) {
180 PRUint32 numNewBlocks
= endIndex
+ 1 - mBlocks
.Length();
181 nsAutoPtr
<Block
> *blocks
= mBlocks
.AppendElements(numNewBlocks
);
182 if (NS_UNLIKELY(!blocks
)) // OOM
186 for (PRUint32 i
= startIndex
; i
<= endIndex
; ++i
) {
187 const PRUint32 blockFirstBit
= i
* BLOCK_SIZE_BITS
;
188 const PRUint32 blockLastBit
= blockFirstBit
+ BLOCK_SIZE_BITS
- 1;
190 Block
*block
= mBlocks
[i
];
192 PRBool fullBlock
= PR_FALSE
;
193 if (aStart
<= blockFirstBit
&& aEnd
>= blockLastBit
)
196 block
= new Block(fullBlock
? 0xFF : 0);
198 if (NS_UNLIKELY(!block
)) // OOM
206 const PRUint32 start
= aStart
> blockFirstBit
? aStart
- blockFirstBit
: 0;
207 const PRUint32 end
= PR_MIN(aEnd
- blockFirstBit
, BLOCK_SIZE_BITS
- 1);
209 for (PRUint32 bit
= start
; bit
<= end
; ++bit
) {
210 block
->mBits
[bit
>>3] |= 1 << (bit
& 0x7);
215 void clear(PRUint32 aIndex
) {
216 PRUint32 blockIndex
= aIndex
/BLOCK_SIZE_BITS
;
217 if (blockIndex
>= mBlocks
.Length()) {
218 nsAutoPtr
<Block
> *blocks
= mBlocks
.AppendElements(blockIndex
+ 1 - mBlocks
.Length());
219 if (NS_UNLIKELY(!blocks
)) // OOM
222 Block
*block
= mBlocks
[blockIndex
];
225 if (NS_UNLIKELY(!block
)) // OOM
227 mBlocks
[blockIndex
] = block
;
229 block
->mBits
[(aIndex
>>3) & (BLOCK_SIZE
- 1)] &= ~(1 << (aIndex
& 0x7));
232 void ClearRange(PRUint32 aStart
, PRUint32 aEnd
) {
233 const PRUint32 startIndex
= aStart
/BLOCK_SIZE_BITS
;
234 const PRUint32 endIndex
= aEnd
/BLOCK_SIZE_BITS
;
236 if (endIndex
>= mBlocks
.Length()) {
237 PRUint32 numNewBlocks
= endIndex
+ 1 - mBlocks
.Length();
238 nsAutoPtr
<Block
> *blocks
= mBlocks
.AppendElements(numNewBlocks
);
239 if (NS_UNLIKELY(!blocks
)) // OOM
243 for (PRUint32 i
= startIndex
; i
<= endIndex
; ++i
) {
244 const PRUint32 blockFirstBit
= i
* BLOCK_SIZE_BITS
;
245 const PRUint32 blockLastBit
= blockFirstBit
+ BLOCK_SIZE_BITS
- 1;
247 Block
*block
= mBlocks
[i
];
249 PRBool fullBlock
= PR_FALSE
;
250 if (aStart
<= blockFirstBit
&& aEnd
>= blockLastBit
)
253 block
= new Block(fullBlock
? 0xFF : 0);
255 if (NS_UNLIKELY(!block
)) // OOM
263 const PRUint32 start
= aStart
> blockFirstBit
? aStart
- blockFirstBit
: 0;
264 const PRUint32 end
= PR_MIN(aEnd
- blockFirstBit
, BLOCK_SIZE_BITS
- 1);
266 for (PRUint32 bit
= start
; bit
<= end
; ++bit
) {
267 block
->mBits
[bit
>>3] &= ~(1 << (bit
& 0x7));
274 for (PRUint32 i
= 0; i
< mBlocks
.Length(); i
++) {
276 size
+= sizeof(Block
);
277 size
+= sizeof(nsAutoPtr
<Block
>);
282 // clear out all blocks in the array
285 for (i
= 0; i
< mBlocks
.Length(); i
++)
289 nsTArray
< nsAutoPtr
<Block
> > mBlocks
;
292 class THEBES_API gfxFontUtils
{
296 // for reading big-endian font data on either big or little-endian platforms
298 static inline PRUint16
299 ReadShortAt(const PRUint8
*aBuf
, PRUint32 aIndex
)
301 return (aBuf
[aIndex
] << 8) | aBuf
[aIndex
+ 1];
304 static inline PRUint16
305 ReadShortAt16(const PRUint16
*aBuf
, PRUint32 aIndex
)
307 const PRUint8
*buf
= (PRUint8
*) aBuf
;
308 PRUint32 index
= aIndex
<< 1;
309 return (buf
[index
] << 8) | buf
[index
+1];
312 static inline PRUint32
313 ReadLongAt(const PRUint8
*aBuf
, PRUint32 aIndex
)
315 return ((aBuf
[aIndex
] << 24) | (aBuf
[aIndex
+ 1] << 16) |
316 (aBuf
[aIndex
+ 2] << 8) | (aBuf
[aIndex
+ 3]));
320 ReadCMAPTableFormat12(PRUint8
*aBuf
, PRUint32 aLength
,
321 gfxSparseBitSet
& aCharacterMap
);
324 ReadCMAPTableFormat4(PRUint8
*aBuf
, PRUint32 aLength
,
325 gfxSparseBitSet
& aCharacterMap
);
328 ReadCMAP(PRUint8
*aBuf
, PRUint32 aBufLength
, gfxSparseBitSet
& aCharacterMap
,
329 PRPackedBool
& aUnicodeFont
, PRPackedBool
& aSymbolFont
);
332 // given a TrueType/OpenType data file, produce a EOT-format header
333 // for use with Windows T2Embed API AddFontResource type API's
334 // effectively hide existing fonts with matching names aHeaderLen is
335 // the size of the header buffer on input, the actual size of the
336 // EOT header on output aIsCFF returns whether the font has PS style
337 // glyphs or not (as opposed to TrueType glyphs)
339 MakeEOTHeader(const PRUint8
*aFontData
, PRUint32 aFontDataLength
,
340 nsTArray
<PRUint8
> *aHeader
, PRBool
*aIsCFF
);
343 // checks for valid SFNT table structure, returns true if valid
344 // does *not* guarantee that all font data is valid
346 ValidateSFNTHeaders(const PRUint8
*aFontData
, PRUint32 aFontDataLength
);
348 static inline bool IsJoiner(PRUint32 ch
) {
349 return (ch
== 0x200C ||
354 static inline bool IsInvalid(PRUint32 ch
) {
355 return (ch
== 0xFFFD);
358 static PRUint8
CharRangeBit(PRUint32 ch
);
360 // for a given font list pref name, set up a list of font names
361 static void GetPrefsFontList(const char *aPrefName
,
362 nsTArray
<nsString
>& aFontList
);
366 // helper class for loading in font info spaced out at regular intervals
368 class gfxFontInfoLoader
{
371 // state transitions:
372 // initial ---StartLoader with delay---> timer on delay
373 // initial ---StartLoader without delay---> timer on interval
374 // timer on delay ---LoaderTimerFire---> timer on interval
375 // timer on delay ---CancelLoader---> timer off
376 // timer on interval ---CancelLoader---> timer off
377 // timer off ---StartLoader with delay---> timer on delay
378 // timer off ---StartLoader without delay---> timer on interval
382 stateTimerOnInterval
,
386 gfxFontInfoLoader() :
387 mInterval(0), mState(stateInitial
)
391 virtual ~gfxFontInfoLoader() {}
393 // start timer with an initial delay, then call Run method at regular intervals
394 void StartLoader(PRUint32 aDelay
, PRUint32 aInterval
) {
395 mInterval
= aInterval
;
398 if (mState
!= stateInitial
&& mState
!= stateTimerOff
)
403 mTimer
= do_CreateInstance("@mozilla.org/timer;1");
405 NS_WARNING("Failure to create font info loader timer");
410 // need an initial delay?
411 PRUint32 timerInterval
;
414 mState
= stateTimerOnDelay
;
415 timerInterval
= aDelay
;
417 mState
= stateTimerOnInterval
;
418 timerInterval
= mInterval
;
424 mTimer
->InitWithFuncCallback(LoaderTimerCallback
, this, aDelay
,
425 nsITimer::TYPE_REPEATING_SLACK
);
428 // cancel the timer and cleanup
429 void CancelLoader() {
430 if (mState
== stateInitial
)
432 mState
= stateTimerOff
;
441 // Init - initialization at start time after initial delay
442 virtual void InitLoader() = 0;
444 // Run - called at intervals, return true to indicate done
445 virtual PRBool
RunLoader() = 0;
447 // Finish - cleanup after done
448 virtual void FinishLoader() = 0;
450 static void LoaderTimerCallback(nsITimer
*aTimer
, void *aThis
) {
451 gfxFontInfoLoader
*loader
= (gfxFontInfoLoader
*) aThis
;
452 loader
->LoaderTimerFire();
455 // start the timer, interval callbacks
456 void LoaderTimerFire() {
457 if (mState
== stateTimerOnDelay
) {
458 mState
= stateTimerOnInterval
;
459 mTimer
->SetDelay(mInterval
);
462 PRBool done
= RunLoader();
468 nsCOMPtr
<nsITimer
> mTimer
;
473 #endif /* GFX_FONT_UTILS_H */