Bug 460926 A11y hierachy is broken on Ubuntu 8.10 (GNOME 2.24), r=Evan.Yan sr=roc
[wine-gecko.git] / gfx / thebes / public / gfxFontUtils.h
blob27f1e4b1f415eb556436b8de7a132b4bc75ab3a8
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
13 * License.
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.
21 * Contributor(s):
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
42 #include "gfxTypes.h"
44 #include "prtypes.h"
45 #include "prcpucfg.h"
47 #include "nsDataHashtable.h"
49 #include "nsITimer.h"
50 #include "nsCOMPtr.h"
51 #include "nsIRunnable.h"
52 #include "nsThreadUtils.h"
53 #include "nsComponentManagerUtils.h"
54 #include "nsTArray.h"
55 #include "nsAutoPtr.h"
57 /* Bug 341128 - w32api defines min/max which causes problems with <bitset> */
58 #ifdef __MINGW32__
59 #undef min
60 #undef max
61 #endif
63 #include <bitset>
65 // code from gfxWindowsFonts.h
67 class gfxSparseBitSet {
68 private:
69 enum { BLOCK_SIZE = 32 }; // ==> 256 codepoints per block
70 enum { BLOCK_SIZE_BITS = BLOCK_SIZE * 8 };
71 enum { BLOCK_INDEX_SHIFT = 8 };
73 struct Block {
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];
79 public:
80 gfxSparseBitSet() { }
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];
86 if (block)
87 mBlocks[i] = new Block(*block);
90 PRBool test(PRUint32 aIndex) {
91 PRUint32 blockIndex = aIndex/BLOCK_SIZE_BITS;
92 if (blockIndex >= mBlocks.Length())
93 return PR_FALSE;
94 Block *block = mBlocks[blockIndex];
95 if (!block)
96 return PR_FALSE;
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
109 PRUint32 blockIndex;
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;
120 Block *block;
121 PRUint32 i, start, end;
123 // first block, check bits
124 if ((block = mBlocks[startBlock])) {
125 start = aStart;
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)))
129 return PR_TRUE;
132 if (endBlock == startBlock) return PR_FALSE;
134 // [2..n-1] blocks check bytes
135 for (blockIndex = startBlock + 1; blockIndex < endBlock; blockIndex++) {
136 PRUint32 index;
138 if (blockIndex >= blockLen || !(block = mBlocks[blockIndex])) continue;
139 for (index = 0; index < BLOCK_SIZE; index++) {
140 if (block->mBits[index])
141 return PR_TRUE;
145 // last block, check bits
146 if (endBlock < blockLen && (block = mBlocks[endBlock])) {
147 start = endBlock << BLOCK_INDEX_SHIFT;
148 end = aEnd;
149 for (i = start; i <= end; i++) {
150 if ((block->mBits[(i>>3) & (BLOCK_SIZE - 1)]) & (1 << (i & 0x7)))
151 return PR_TRUE;
155 return PR_FALSE;
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
163 return;
165 Block *block = mBlocks[blockIndex];
166 if (!block) {
167 block = new Block;
168 if (NS_UNLIKELY(!block)) // OOM
169 return;
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
183 return;
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];
191 if (!block) {
192 PRBool fullBlock = PR_FALSE;
193 if (aStart <= blockFirstBit && aEnd >= blockLastBit)
194 fullBlock = PR_TRUE;
196 block = new Block(fullBlock ? 0xFF : 0);
198 if (NS_UNLIKELY(!block)) // OOM
199 return;
200 mBlocks[i] = block;
202 if (fullBlock)
203 continue;
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
220 return;
222 Block *block = mBlocks[blockIndex];
223 if (!block) {
224 block = new Block;
225 if (NS_UNLIKELY(!block)) // OOM
226 return;
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
240 return;
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];
248 if (!block) {
249 PRBool fullBlock = PR_FALSE;
250 if (aStart <= blockFirstBit && aEnd >= blockLastBit)
251 fullBlock = PR_TRUE;
253 block = new Block(fullBlock ? 0xFF : 0);
255 if (NS_UNLIKELY(!block)) // OOM
256 return;
257 mBlocks[i] = block;
259 if (fullBlock)
260 continue;
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));
272 PRUint32 GetSize() {
273 PRUint32 size = 0;
274 for (PRUint32 i = 0; i < mBlocks.Length(); i++) {
275 if (mBlocks[i])
276 size += sizeof(Block);
277 size += sizeof(nsAutoPtr<Block>);
279 return size;
282 // clear out all blocks in the array
283 void reset() {
284 PRUint32 i;
285 for (i = 0; i < mBlocks.Length(); i++)
286 mBlocks[i] = nsnull;
289 nsTArray< nsAutoPtr<Block> > mBlocks;
292 class THEBES_API gfxFontUtils {
294 public:
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]));
319 static nsresult
320 ReadCMAPTableFormat12(PRUint8 *aBuf, PRUint32 aLength,
321 gfxSparseBitSet& aCharacterMap);
323 static nsresult
324 ReadCMAPTableFormat4(PRUint8 *aBuf, PRUint32 aLength,
325 gfxSparseBitSet& aCharacterMap);
327 static nsresult
328 ReadCMAP(PRUint8 *aBuf, PRUint32 aBufLength, gfxSparseBitSet& aCharacterMap,
329 PRPackedBool& aUnicodeFont, PRPackedBool& aSymbolFont);
331 #ifdef XP_WIN
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)
338 static nsresult
339 MakeEOTHeader(const PRUint8 *aFontData, PRUint32 aFontDataLength,
340 nsTArray<PRUint8> *aHeader, PRBool *aIsCFF);
341 #endif
343 // checks for valid SFNT table structure, returns true if valid
344 // does *not* guarantee that all font data is valid
345 static PRBool
346 ValidateSFNTHeaders(const PRUint8 *aFontData, PRUint32 aFontDataLength);
348 static inline bool IsJoiner(PRUint32 ch) {
349 return (ch == 0x200C ||
350 ch == 0x200D ||
351 ch == 0x2060);
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 {
369 public:
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
379 typedef enum {
380 stateInitial,
381 stateTimerOnDelay,
382 stateTimerOnInterval,
383 stateTimerOff
384 } TimerState;
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;
397 // sanity check
398 if (mState != stateInitial && mState != stateTimerOff)
399 CancelLoader();
401 // set up timer
402 if (!mTimer) {
403 mTimer = do_CreateInstance("@mozilla.org/timer;1");
404 if (!mTimer) {
405 NS_WARNING("Failure to create font info loader timer");
406 return;
410 // need an initial delay?
411 PRUint32 timerInterval;
413 if (aDelay) {
414 mState = stateTimerOnDelay;
415 timerInterval = aDelay;
416 } else {
417 mState = stateTimerOnInterval;
418 timerInterval = mInterval;
421 InitLoader();
423 // start timer
424 mTimer->InitWithFuncCallback(LoaderTimerCallback, this, aDelay,
425 nsITimer::TYPE_REPEATING_SLACK);
428 // cancel the timer and cleanup
429 void CancelLoader() {
430 if (mState == stateInitial)
431 return;
432 mState = stateTimerOff;
433 if (mTimer) {
434 mTimer->Cancel();
436 FinishLoader();
439 protected:
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();
463 if (done) {
464 CancelLoader();
468 nsCOMPtr<nsITimer> mTimer;
469 PRUint32 mInterval;
470 TimerState mState;
473 #endif /* GFX_FONT_UTILS_H */