44e33a4b42784774029e3b70c64cbc1d9d666e7a
[WebKit-https.git] / WebCore / platform / mac / FontData.mm
1 /*
2  * Copyright (C) 2005 Apple Computer, Inc.  All rights reserved.
3  * Copyright (C) 2006 Alexey Proskuryakov
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1.  Redistributions of source code must retain the above copyright
10  *     notice, this list of conditions and the following disclaimer. 
11  * 2.  Redistributions in binary form must reproduce the above copyright
12  *     notice, this list of conditions and the following disclaimer in the
13  *     documentation and/or other materials provided with the distribution. 
14  * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
15  *     its contributors may be used to endorse or promote products derived
16  *     from this software without specific prior written permission. 
17  *
18  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
19  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
22  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29
30 #import "config.h"
31 #import "Font.h"
32 #import "FontData.h"
33 #import "Color.h"
34 #import "WebCoreTextRenderer.h"
35
36 #import <wtf/Assertions.h>
37
38 #import <ApplicationServices/ApplicationServices.h>
39 #import <Cocoa/Cocoa.h>
40
41 #import <WebTextRendererFactory.h>
42
43 #import "WebCoreSystemInterface.h"
44
45 #import "FloatRect.h"
46 #import "FontDescription.h"
47
48 #import <float.h>
49
50 #import <unicode/uchar.h>
51 #import <unicode/unorm.h>
52
53 // FIXME: Just temporary for the #defines of constants that we will eventually stop using.
54 #import "GlyphBuffer.h"
55
56 namespace WebCore
57 {
58
59 // FIXME: FATAL seems like a bad idea; lets stop using it.
60
61 #define SMALLCAPS_FONTSIZE_MULTIPLIER 0.7f
62 #define SYNTHETIC_OBLIQUE_ANGLE 14
63
64 // Should be more than enough for normal usage.
65 #define NUM_SUBSTITUTE_FONT_MAPS 10
66
67 // According to http://www.unicode.org/Public/UNIDATA/UCD.html#Canonical_Combining_Class_Values
68 #define HIRAGANA_KATAKANA_VOICING_MARKS 8
69
70 #define SPACE 0x0020
71 #define NO_BREAK_SPACE 0x00A0
72 #define ZERO_WIDTH_SPACE 0x200B
73 #define POP_DIRECTIONAL_FORMATTING 0x202C
74 #define LEFT_TO_RIGHT_OVERRIDE 0x202D
75 #define RIGHT_TO_LEFT_OVERRIDE 0x202E
76
77 // MAX_GLYPH_EXPANSION is the maximum numbers of glyphs that may be
78 // use to represent a single Unicode code point.
79 #define MAX_GLYPH_EXPANSION 4
80 #define LOCAL_BUFFER_SIZE 2048
81
82 // Covers Latin-1.
83 #define INITIAL_BLOCK_SIZE 0x200
84
85 // Get additional blocks of glyphs and widths in bigger chunks.
86 // This will typically be for other character sets.
87 #define INCREMENTAL_BLOCK_SIZE 0x400
88
89 #define CONTEXT_DPI (72.0)
90 #define SCALE_EM_TO_UNITS(X, U_PER_EM) (X * ((1.0 * CONTEXT_DPI) / (CONTEXT_DPI * U_PER_EM)))
91
92 #define WKGlyphVectorSize (50 * 32)
93
94 typedef float WebGlyphWidth;
95
96 struct WidthMap {
97     WidthMap() :next(0), widths(0) {}
98
99     ATSGlyphRef startRange;
100     ATSGlyphRef endRange;
101     WidthMap *next;
102     WebGlyphWidth *widths;
103 };
104
105 typedef struct GlyphEntry {
106     Glyph glyph;
107     const FontData *renderer;
108 } GlyphEntry;
109
110 struct GlyphMap {
111     UChar startRange;
112     UChar endRange;
113     GlyphMap *next;
114     GlyphEntry *glyphs;
115 };
116
117 typedef struct WidthIterator {
118     FontData *renderer;
119     const WebCoreTextRun *run;
120     const WebCoreTextStyle *style;
121     unsigned currentCharacter;
122     float runWidthSoFar;
123     float widthToStart;
124     float padding;
125     float padPerSpace;
126     float finalRoundingWidth;
127 } WidthIterator;
128
129 typedef struct ATSULayoutParameters
130 {
131     const WebCoreTextRun *run;
132     const WebCoreTextStyle *style;
133     ATSUTextLayout layout;
134     FontData **renderers;
135     UniChar *charBuffer;
136     bool hasSyntheticBold;
137     bool syntheticBoldPass;
138     float padPerSpace;
139 } ATSULayoutParameters;
140
141 static const FontData *rendererForAlternateFont(const FontData *, FontPlatformData);
142
143 static WidthMap *extendWidthMap(const FontData *, ATSGlyphRef);
144 static ATSGlyphRef extendGlyphMap(const FontData *, UChar32);
145
146 static void freeWidthMap(WidthMap *);
147 static void freeGlyphMap(GlyphMap *);
148
149 // Measuring runs.
150 static float CG_floatWidthForRun(FontData *, const WebCoreTextRun *, const WebCoreTextStyle *,
151     float *widthBuffer, FontData **rendererBuffer, CGGlyph *glyphBuffer, float *startPosition, int *numGlyphsResult);
152 static float ATSU_floatWidthForRun(FontData *, const WebCoreTextRun *, const WebCoreTextStyle *);
153
154 // Drawing runs.
155 static void CG_draw(FontData *, const WebCoreTextRun *, const WebCoreTextStyle *, const WebCoreTextGeometry *);
156 static void ATSU_draw(FontData *, const WebCoreTextRun *, const WebCoreTextStyle *, const WebCoreTextGeometry *);
157
158 // Selection point detection in runs.
159 static int CG_pointToOffset(FontData *, const WebCoreTextRun *, const WebCoreTextStyle *,
160     int x, bool includePartialGlyphs);
161 static int ATSU_pointToOffset(FontData *, const WebCoreTextRun *, const WebCoreTextStyle *,
162     int x, bool includePartialGlyphs);
163
164 // Selection rect.
165 static NSRect CG_selectionRect(FontData *, const WebCoreTextRun *, const WebCoreTextStyle *, const WebCoreTextGeometry *);
166 static NSRect ATSU_selectionRect(FontData *, const WebCoreTextRun *, const WebCoreTextStyle *, const WebCoreTextGeometry *);
167
168 // Drawing highlight.
169 static void CG_drawHighlight(FontData *, const WebCoreTextRun *, const WebCoreTextStyle *, const WebCoreTextGeometry *);
170 static void ATSU_drawHighlight(FontData *, const WebCoreTextRun *, const WebCoreTextStyle *, const WebCoreTextGeometry *);
171
172 static bool setUpFont(FontData *);
173
174 // Iterator functions
175 static void initializeWidthIterator(WidthIterator *iterator, FontData *renderer, const WebCoreTextRun *run, const WebCoreTextStyle *style);
176 static unsigned advanceWidthIterator(WidthIterator *iterator, unsigned offset, float *widths, FontData **renderersUsed, ATSGlyphRef *glyphsUsed);
177
178 static bool fillStyleWithAttributes(ATSUStyle style, NSFont *theFont);
179 static bool shouldUseATSU(const WebCoreTextRun *run);
180
181 #if !ERROR_DISABLED
182 static NSString *pathFromFont(NSFont *font);
183 #endif
184
185 static void createATSULayoutParameters(ATSULayoutParameters *params, FontData *renderer, const WebCoreTextRun *run, const WebCoreTextStyle *style);
186 static void disposeATSULayoutParameters(ATSULayoutParameters *params);
187
188 // Character property functions.
189
190 inline bool isSpace(UChar32 c)
191 {
192     return c == SPACE || c == '\t' || c == '\n' || c == NO_BREAK_SPACE;
193 }
194
195 static const uint8_t isRoundingHackCharacterTable[0x100] = {
196     0, 0, 0, 0, 0, 0, 0, 0, 0, 1 /*\t*/, 1 /*\n*/, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
197     1 /*space*/, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 /*-*/, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 /*?*/,
198     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
199     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
200     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
201     1 /*no-break space*/, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
202     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
203     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
204 };
205
206 bool isRoundingHackCharacter(UChar c)
207 {
208     return (((c & ~0xFF) == 0 && isRoundingHackCharacterTable[c]));
209 }
210
211 void WebCoreInitializeFont(FontPlatformData *font)
212 {
213     font->font = nil;
214     font->syntheticBold = NO;
215     font->syntheticOblique = NO;
216     font->forPrinter = NO;
217 }
218
219 void WebCoreInitializeTextRun(WebCoreTextRun *run, const UniChar *characters, unsigned int length, int from, int to)
220 {
221     run->characters = characters;
222     run->length = length;
223     run->from = from;
224     run->to = to;
225 }
226
227 void WebCoreInitializeEmptyTextStyle(WebCoreTextStyle *style)
228 {
229     style->textColor = nil;
230     style->backgroundColor = nil;
231     style->letterSpacing = 0;
232     style->wordSpacing = 0;
233     style->padding = 0;
234     style->families = nil;
235     style->smallCaps = NO;
236     style->rtl = NO;
237     style->directionalOverride = NO;
238     style->applyRunRounding = YES;
239     style->applyWordRounding = YES;
240     style->attemptFontSubstitution = YES;
241 }
242
243 void WebCoreInitializeEmptyTextGeometry(WebCoreTextGeometry *geometry)
244 {
245     geometry->useFontMetricsForSelectionYAndHeight = YES;
246 }
247
248 // Map utility functions
249
250 float FontData::widthForGlyph(Glyph glyph) const
251 {
252     WidthMap *map;
253     for (map = m_glyphToWidthMap; 1; map = map->next) {
254         if (!map)
255             map = extendWidthMap(this, glyph);
256         if (glyph >= map->startRange && glyph <= map->endRange)
257             break;
258     }
259     float width = map->widths[glyph - map->startRange];
260     if (width >= 0)
261         return width;
262     NSFont *font = m_font.font;
263     float pointSize = [font pointSize];
264     CGAffineTransform m = CGAffineTransformMakeScale(pointSize, pointSize);
265     CGSize advance;
266     if (!wkGetGlyphTransformedAdvances(font, &m, &glyph, &advance)) {
267         LOG_ERROR("Unable to cache glyph widths for %@ %f", [font displayName], pointSize);
268         advance.width = 0;
269     }
270     width = advance.width + m_syntheticBoldOffset;
271     map->widths[glyph - map->startRange] = width;
272     return width;
273 }
274
275 static OSStatus overrideLayoutOperation(ATSULayoutOperationSelector iCurrentOperation, ATSULineRef iLineRef, UInt32 iRefCon, void *iOperationCallbackParameterPtr, ATSULayoutOperationCallbackStatus *oCallbackStatus)
276 {
277     ATSULayoutParameters *params = (ATSULayoutParameters *)iRefCon;
278     OSStatus status;
279     ItemCount count;
280     ATSLayoutRecord *layoutRecords;
281     const WebCoreTextStyle *style = params->style;
282
283     if (style->applyWordRounding) {
284         status = ATSUDirectGetLayoutDataArrayPtrFromLineRef(iLineRef, kATSUDirectDataLayoutRecordATSLayoutRecordCurrent, true, (void **)&layoutRecords, &count);
285         if (status != noErr) {
286             *oCallbackStatus = kATSULayoutOperationCallbackStatusContinue;
287             return status;
288         }
289         
290         Fixed lastNativePos = 0;
291         float lastAdjustedPos = 0;
292         const WebCoreTextRun *run = params->run;
293         const UniChar *characters = run->characters + run->from;
294         FontData **renderers = params->renderers + run->from;
295         FontData *renderer;
296         FontData *lastRenderer = 0;
297         UniChar ch, nextCh;
298         ByteCount offset = layoutRecords[0].originalOffset;
299         nextCh = *(UniChar *)(((char *)characters)+offset);
300         bool shouldRound = false;
301         bool syntheticBoldPass = params->syntheticBoldPass;
302         Fixed syntheticBoldOffset = 0;
303         ATSGlyphRef spaceGlyph = 0;
304         bool hasExtraSpacing = style->letterSpacing | style->wordSpacing | style->padding;
305         float padding = style->padding;
306         // In the CoreGraphics code path, the rounding hack is applied in logical order.
307         // Here it is applied in visual left-to-right order, which may be better.
308         ItemCount lastRoundingChar = 0;
309         ItemCount i;
310         for (i = 1; i < count; i++) {
311             bool isLastChar = i == count - 1;
312             renderer = renderers[offset / 2];
313             if (renderer != lastRenderer) {
314                 lastRenderer = renderer;
315                 // The CoreGraphics interpretation of NSFontAntialiasedIntegerAdvancementsRenderingMode seems
316                 // to be "round each glyph's width to the nearest integer". This is not the same as ATSUI
317                 // does in any of its device-metrics modes.
318                 shouldRound = [renderer->m_font.font renderingMode] == NSFontAntialiasedIntegerAdvancementsRenderingMode;
319                 if (syntheticBoldPass) {
320                     syntheticBoldOffset = FloatToFixed(renderer->m_syntheticBoldOffset);
321                     spaceGlyph = renderer->m_spaceGlyph;
322                 }
323             }
324             float width = FixedToFloat(layoutRecords[i].realPos - lastNativePos);
325             lastNativePos = layoutRecords[i].realPos;
326             if (shouldRound)
327                 width = roundf(width);
328             width += renderer->m_syntheticBoldOffset;
329             if (renderer->m_treatAsFixedPitch ? width == renderer->m_spaceWidth : (layoutRecords[i-1].flags & kATSGlyphInfoIsWhiteSpace))
330                 width = renderer->m_adjustedSpaceWidth;
331
332             if (hasExtraSpacing) {
333                 if (width && style->letterSpacing)
334                     width +=style->letterSpacing;
335                 if (isSpace(nextCh)) {
336                     if (style->padding) {
337                         if (padding < params->padPerSpace) {
338                             width += padding;
339                             padding = 0;
340                         } else {
341                             width += params->padPerSpace;
342                             padding -= params->padPerSpace;
343                         }
344                     }
345                     if (offset != 0 && !isSpace(*((UniChar *)(((char *)characters)+offset) - 1)) && style->wordSpacing)
346                         width += style->wordSpacing;
347                 }
348             }
349
350             ch = nextCh;
351             offset = layoutRecords[i].originalOffset;
352             // Use space for nextCh at the end of the loop so that we get inside the rounding hack code.
353             // We won't actually round unless the other conditions are satisfied.
354             nextCh = isLastChar ? ' ' : *(UniChar *)(((char *)characters)+offset);
355
356             if (isRoundingHackCharacter(ch))
357                 width = ceilf(width);
358             lastAdjustedPos = lastAdjustedPos + width;
359             if (isRoundingHackCharacter(nextCh)
360                 && (!isLastChar
361                     || style->applyRunRounding
362                     || (run->to < (int)run->length && isRoundingHackCharacter(characters[run->to - run->from])))) {
363                 if (!style->rtl)
364                     lastAdjustedPos = ceilf(lastAdjustedPos);
365                 else {
366                     float roundingWidth = ceilf(lastAdjustedPos) - lastAdjustedPos;
367                     Fixed rw = FloatToFixed(roundingWidth);
368                     ItemCount j;
369                     for (j = lastRoundingChar; j < i; j++)
370                         layoutRecords[j].realPos += rw;
371                     lastRoundingChar = i;
372                     lastAdjustedPos += roundingWidth;
373                 }
374             }
375             if (syntheticBoldPass) {
376                 if (syntheticBoldOffset)
377                     layoutRecords[i-1].realPos += syntheticBoldOffset;
378                 else
379                     layoutRecords[i-1].glyphID = spaceGlyph;
380             }
381             layoutRecords[i].realPos = FloatToFixed(lastAdjustedPos);
382         }
383         
384         status = ATSUDirectReleaseLayoutDataArrayPtr(iLineRef, kATSUDirectDataLayoutRecordATSLayoutRecordCurrent, (void **)&layoutRecords);
385     }
386     *oCallbackStatus = kATSULayoutOperationCallbackStatusHandled;
387     return noErr;
388 }
389
390 static NSString *webFallbackFontFamily(void)
391 {
392     static NSString *webFallbackFontFamily = nil;
393     if (!webFallbackFontFamily)
394         webFallbackFontFamily = [[[NSFont systemFontOfSize:16.0] familyName] retain];
395     return webFallbackFontFamily;
396 }
397
398 FontData::FontData(const FontPlatformData& f)
399 :m_styleGroup(0), m_font(f), m_characterToGlyphMap(0), m_glyphToWidthMap(0), m_treatAsFixedPitch(false),
400  m_smallCapsFontData(0), m_ATSUStyleInitialized(false), m_ATSUMirrors(false)
401 {    
402     m_font = f;
403
404     m_syntheticBoldOffset = f.syntheticBold ? ceilf([f.font pointSize] / 24.0f) : 0.f;
405     
406     bool failedSetup = false;
407     if (!setUpFont(this)) {
408         // Ack! Something very bad happened, like a corrupt font.
409         // Try looking for an alternate 'base' font for this renderer.
410
411         // Special case hack to use "Times New Roman" in place of "Times".
412         // "Times RO" is a common font whose family name is "Times".
413         // It overrides the normal "Times" family font.
414         // It also appears to have a corrupt regular variant.
415         NSString *fallbackFontFamily;
416         if ([[m_font.font familyName] isEqual:@"Times"])
417             fallbackFontFamily = @"Times New Roman";
418         else
419             fallbackFontFamily = webFallbackFontFamily();
420         
421         // Try setting up the alternate font.
422         // This is a last ditch effort to use a substitute font when something has gone wrong.
423 #if !ERROR_DISABLED
424         NSFont *initialFont = m_font.font;
425 #endif
426         m_font.font = [[NSFontManager sharedFontManager] convertFont:m_font.font toFamily:fallbackFontFamily];
427 #if !ERROR_DISABLED
428         NSString *filePath = pathFromFont(initialFont);
429         if (!filePath)
430             filePath = @"not known";
431 #endif
432         if (!setUpFont(this)) {
433             if ([fallbackFontFamily isEqual:@"Times New Roman"]) {
434                 // OK, couldn't setup Times New Roman as an alternate to Times, fallback
435                 // on the system font.  If this fails we have no alternative left.
436                 m_font.font = [[NSFontManager sharedFontManager] convertFont:m_font.font toFamily:webFallbackFontFamily()];
437                 if (!setUpFont(this)) {
438                     // We tried, Times, Times New Roman, and the system font. No joy. We have to give up.
439                     LOG_ERROR("unable to initialize with font %@ at %@", initialFont, filePath);
440                     failedSetup = true;
441                 }
442             } else {
443                 // We tried the requested font and the system font. No joy. We have to give up.
444                 LOG_ERROR("unable to initialize with font %@ at %@", initialFont, filePath);
445                 failedSetup = true;
446             }
447         }
448
449         // Report the problem.
450         LOG_ERROR("Corrupt font detected, using %@ in place of %@ located at \"%@\".",
451             [m_font.font familyName], [initialFont familyName], filePath);
452     }
453
454     // If all else fails, try to set up using the system font.
455     // This is probably because Times and Times New Roman are both unavailable.
456     if (failedSetup) {
457         m_font.font = [NSFont systemFontOfSize:[m_font.font pointSize]];
458         LOG_ERROR("failed to set up font, using system font %s", m_font.font);
459         setUpFont(this);
460     }
461     
462     int iAscent;
463     int iDescent;
464     int iLineGap;
465     unsigned unitsPerEm;
466     wkGetFontMetrics(m_font.font, &iAscent, &iDescent, &iLineGap, &unitsPerEm); 
467     float pointSize = [m_font.font pointSize];
468     float fAscent = SCALE_EM_TO_UNITS(iAscent, unitsPerEm) * pointSize;
469     float fDescent = -SCALE_EM_TO_UNITS(iDescent, unitsPerEm) * pointSize;
470     float fLineGap = SCALE_EM_TO_UNITS(iLineGap, unitsPerEm) * pointSize;
471
472     // We need to adjust Times, Helvetica, and Courier to closely match the
473     // vertical metrics of their Microsoft counterparts that are the de facto
474     // web standard. The AppKit adjustment of 20% is too big and is
475     // incorrectly added to line spacing, so we use a 15% adjustment instead
476     // and add it to the ascent.
477     NSString *familyName = [m_font.font familyName];
478     if ([familyName isEqualToString:@"Times"] || [familyName isEqualToString:@"Helvetica"] || [familyName isEqualToString:@"Courier"])
479         fAscent += floorf(((fAscent + fDescent) * 0.15f) + 0.5f);
480
481     m_ascent = lroundf(fAscent);
482     m_descent = lroundf(fDescent);
483     m_lineGap = lroundf(fLineGap);
484
485     m_lineSpacing = m_ascent + m_descent + m_lineGap;
486
487     [m_font.font retain];
488 }
489
490 FontData::~FontData()
491 {
492     if (m_styleGroup)
493         wkReleaseStyleGroup(m_styleGroup);
494
495     freeWidthMap(m_glyphToWidthMap);
496     freeGlyphMap(m_characterToGlyphMap);
497
498     if (m_ATSUStyleInitialized)
499         ATSUDisposeStyle(m_ATSUStyle);
500         
501     [m_font.font release];
502     
503     // We only get deleted when the cache gets cleared.  Since the smallCapsRenderer is also in that cache,
504     // it will be deleted then, so we don't need to do anything here.
505 }
506
507 float FontData::xHeight() const
508 {
509     // Measure the actual character "x", because AppKit synthesizes X height rather than getting it from the font.
510     // Unfortunately, NSFont will round this for us so we don't quite get the right value.
511     const FontData *renderer = [[WebTextRendererFactory sharedFactory] rendererWithFont:m_font];
512     NSGlyph xGlyph = glyphForCharacter(&renderer, 'x');
513     if (xGlyph) {
514         NSRect xBox = [m_font.font boundingRectForGlyph:xGlyph];
515         // Use the maximum of either width or height because "x" is nearly square
516         // and web pages that foolishly use this metric for width will be laid out
517         // poorly if we return an accurate height. Classic case is Times 13 point,
518         // which has an "x" that is 7x6 pixels.
519         return MAX(NSMaxX(xBox), NSMaxY(xBox));
520     }
521
522     return [m_font.font xHeight];
523 }
524
525 void FontData::drawRun(const WebCoreTextRun* run, const WebCoreTextStyle* style, const WebCoreTextGeometry* geometry)
526 {
527     if (shouldUseATSU(run))
528         ATSU_draw(this, run, style, geometry);
529     else
530         CG_draw(this, run, style, geometry);
531 }
532
533 float FontData::floatWidthForRun(const WebCoreTextRun* run, const WebCoreTextStyle* style)
534 {
535     if (shouldUseATSU(run))
536         return ATSU_floatWidthForRun(this, run, style);
537     return CG_floatWidthForRun(this, run, style, 0, 0, 0, 0, 0);
538 }
539
540 static void drawHorizontalLine(float x, float y, float width, NSColor *color, float thickness, bool shouldAntialias)
541 {
542     NSGraphicsContext *graphicsContext = [NSGraphicsContext currentContext];
543     CGContextRef cgContext = (CGContextRef)[graphicsContext graphicsPort];
544
545     CGContextSaveGState(cgContext);
546
547     [color set];
548     CGContextSetLineWidth(cgContext, thickness);
549     CGContextSetShouldAntialias(cgContext, shouldAntialias);
550
551     float halfThickness = thickness / 2;
552
553     CGPoint linePoints[2];
554     linePoints[0].x = x + halfThickness;
555     linePoints[0].y = y + halfThickness;
556     linePoints[1].x = x + width - halfThickness;
557     linePoints[1].y = y + halfThickness;
558     CGContextStrokeLineSegments(cgContext, linePoints, 2);
559
560     CGContextRestoreGState(cgContext);
561 }
562
563 void FontData::drawLineForCharacters(const FloatPoint& point, float yOffset, int width, const Color& color, float thickness)
564 {
565     // Note: This function assumes that point.x and point.y are integers (and that's currently always the case).
566
567     NSGraphicsContext *graphicsContext = [NSGraphicsContext currentContext];
568     CGContextRef cgContext = (CGContextRef)[graphicsContext graphicsPort];
569
570     bool printing = ![graphicsContext isDrawingToScreen];
571
572     float x = point.x();
573     float y = point.y() + yOffset;
574
575     // Leave 1.0 in user space between the baseline of the text and the top of the underline.
576     // FIXME: Is this the right distance for space above the underline? Even for thick underlines on large sized text?
577     y += 1;
578
579     if (printing) {
580         // When printing, use a minimum thickness of 0.5 in user space.
581         // See bugzilla bug 4255 for details of why 0.5 is the right minimum thickness to use while printing.
582         if (thickness < 0.5)
583             thickness = 0.5;
584
585         // When printing, use antialiasing instead of putting things on integral pixel boundaries.
586     } else {
587         // On screen, use a minimum thickness of 1.0 in user space (later rounded to an integral number in device space).
588         if (thickness < 1)
589             thickness = 1;
590
591         // On screen, round all parameters to integer boundaries in device space.
592         CGRect lineRect = CGContextConvertRectToDeviceSpace(cgContext, CGRectMake(x, y, width, thickness));
593         lineRect.origin.x = roundf(lineRect.origin.x);
594         lineRect.origin.y = roundf(lineRect.origin.y);
595         lineRect.size.width = roundf(lineRect.size.width);
596         lineRect.size.height = roundf(lineRect.size.height);
597         if (lineRect.size.height == 0) // don't let thickness round down to 0 pixels
598             lineRect.size.height = 1;
599         lineRect = CGContextConvertRectToUserSpace(cgContext, lineRect);
600         x = lineRect.origin.x;
601         y = lineRect.origin.y;
602         width = (int)(lineRect.size.width);
603         thickness = lineRect.size.height;
604     }
605
606     // FIXME: How about using a rectangle fill instead of drawing a line?
607     drawHorizontalLine(x, y, width, nsColor(color), thickness, printing);
608 }
609
610 FloatRect FontData::selectionRectForRun(const WebCoreTextRun* run, const WebCoreTextStyle* style, const WebCoreTextGeometry* geometry)
611 {
612     if (shouldUseATSU(run))
613         return ATSU_selectionRect(this, run, style, geometry);
614     else
615         return CG_selectionRect(this, run, style, geometry);
616 }
617
618 void FontData::drawHighlightForRun(const WebCoreTextRun* run, const WebCoreTextStyle* style, const WebCoreTextGeometry* geometry)
619 {
620     if (shouldUseATSU(run))
621         ATSU_drawHighlight(this, run, style, geometry);
622     else
623         CG_drawHighlight(this, run, style, geometry);
624 }
625
626 void FontData::drawLineForMisspelling(const FloatPoint& point, int width)
627 {
628     // Constants for pattern color
629     static NSColor *spellingPatternColor = nil;
630     static bool usingDot = false;
631     int patternHeight = misspellingLineThickness();
632     int patternWidth = misspellingLinePatternWidth();
633  
634     // Initialize pattern color if needed
635     if (!spellingPatternColor) {
636         NSImage *image = [NSImage imageNamed:@"SpellingDot"];
637         assert(image); // if image is not available, we want to know
638         NSColor *color = (image ? [NSColor colorWithPatternImage:image] : nil);
639         if (color)
640             usingDot = true;
641         else
642             color = [NSColor redColor];
643         spellingPatternColor = [color retain];
644     }
645
646     // Make sure to draw only complete dots.
647     // NOTE: Code here used to shift the underline to the left and increase the width
648     // to make sure everything gets underlined, but that results in drawing out of
649     // bounds (e.g. when at the edge of a view) and could make it appear that the
650     // space between adjacent misspelled words was underlined.
651     if (usingDot) {
652         // allow slightly more considering that the pattern ends with a transparent pixel
653         int widthMod = width % patternWidth;
654         if (patternWidth - widthMod > misspellingLinePatternGapWidth())
655             width -= widthMod;
656     }
657     
658     // Draw underline
659     NSGraphicsContext *currentContext = [NSGraphicsContext currentContext];
660     CGContextRef context = (CGContextRef)[currentContext graphicsPort];
661     CGContextSaveGState(context);
662
663     [spellingPatternColor set];
664
665     CGPoint transformedOrigin = CGPointApplyAffineTransform(point, CGContextGetCTM(context));
666     CGContextSetPatternPhase(context, CGSizeMake(transformedOrigin.x, transformedOrigin.y));
667
668     NSRectFillUsingOperation(NSMakeRect(point.x(), point.y(), width, patternHeight), NSCompositeSourceOver);
669     
670     CGContextRestoreGState(context);
671 }
672
673 int FontData::pointToOffset(const WebCoreTextRun* run, const WebCoreTextStyle* style, int x, bool includePartialGlyphs)
674 {
675     if (shouldUseATSU(run))
676         return ATSU_pointToOffset(this, run, style, x, includePartialGlyphs);
677     return CG_pointToOffset(this, run, style, x, includePartialGlyphs);
678 }
679
680 FontData* FontData::smallCapsFontData() const
681 {
682     if (!m_smallCapsFontData) {
683         NS_DURING
684             float size = [m_font.font pointSize] * SMALLCAPS_FONTSIZE_MULTIPLIER;
685             FontPlatformData smallCapsFont;
686             WebCoreInitializeFont(&smallCapsFont);
687             smallCapsFont.font = [[NSFontManager sharedFontManager] convertFont:m_font.font toSize:size];
688             m_smallCapsFontData = (FontData*)rendererForAlternateFont(this, smallCapsFont);
689         NS_HANDLER
690             NSLog(@"uncaught exception selecting font for small caps: %@", localException);
691         NS_ENDHANDLER
692     }
693     return m_smallCapsFontData;
694 }
695
696 static inline bool fontContainsString(NSFont *font, NSString *string)
697 {
698     NSCharacterSet *set = [[font coveredCharacterSet] invertedSet];
699     return set && [string rangeOfCharacterFromSet:set].location == NSNotFound;
700 }
701
702 static NSFont *findSubstituteFont(const FontData *renderer, NSString *string, NSString **families)
703 {
704     NSFont *substituteFont = nil;
705
706     // First search the CSS family fallback list.
707     // Start at 1 (2nd font) because we've already failed on the first lookup.
708     NSString *family = nil;
709     int i = 1;
710     while (families && families[i]) {
711         family = families[i++];
712         NSFont *f = [[WebTextRendererFactory sharedFactory] cachedFontFromFamily:family
713             traits:[[NSFontManager sharedFontManager] traitsOfFont:renderer->m_font.font]
714             size:[renderer->m_font.font pointSize]];
715         if (f && fontContainsString(f, string)) {
716             substituteFont = f; 
717             break;
718         }
719     }
720     
721     // Now do string based lookup.
722     if (substituteFont == nil)
723         substituteFont = wkGetFontInLanguageForRange(renderer->m_font.font, string, NSMakeRange(0, [string length]));
724
725     // Now do character based lookup.
726     if (substituteFont == nil && [string length] == 1)
727         substituteFont = wkGetFontInLanguageForCharacter(renderer->m_font.font, [string characterAtIndex:0]);
728
729     // Check to make sure this is a distinct font.
730     if (substituteFont && [[substituteFont screenFont] isEqual:[renderer->m_font.font screenFont]])
731         substituteFont = nil;
732
733     // Now that we have a substitute font, attempt to match it to the best variation.
734     // If we have a good match return that, otherwise return the font the AppKit has found.
735     if (substituteFont) {
736         NSFontManager *manager = [NSFontManager sharedFontManager];
737         NSFont *bestVariation = [manager fontWithFamily:[substituteFont familyName]
738             traits:[manager traitsOfFont:renderer->m_font.font]
739             weight:[manager weightOfFont:renderer->m_font.font]
740             size:[renderer->m_font.font pointSize]];
741         if (bestVariation)
742             substituteFont = bestVariation;
743     }
744
745     return substituteFont;
746 }
747
748 static const FontData *rendererForAlternateFont(const FontData *renderer, FontPlatformData alternateFont)
749 {
750     if (!alternateFont.font)
751         return nil;
752
753     NSFontManager *fontManager = [NSFontManager sharedFontManager];
754     NSFontTraitMask fontTraits = [fontManager traitsOfFont:renderer->m_font.font];
755     if (renderer->m_font.syntheticBold)
756         fontTraits |= NSBoldFontMask;
757     if (renderer->m_font.syntheticOblique)
758         fontTraits |= NSItalicFontMask;
759     NSFontTraitMask alternateFontTraits = [fontManager traitsOfFont:alternateFont.font];
760
761     alternateFont.syntheticBold = (fontTraits & NSBoldFontMask) && !(alternateFontTraits & NSBoldFontMask);
762     alternateFont.syntheticOblique = (fontTraits & NSItalicFontMask) && !(alternateFontTraits & NSItalicFontMask);
763     alternateFont.forPrinter = renderer->m_font.forPrinter;
764
765     return [[WebTextRendererFactory sharedFactory] rendererWithFont:alternateFont];
766 }
767
768 static const FontData *findSubstituteRenderer(const FontData *renderer, const unichar *characters, int numCharacters, NSString **families)
769 {
770     FontPlatformData substituteFont;
771     WebCoreInitializeFont(&substituteFont);
772     NSString *string = [[NSString alloc] initWithCharactersNoCopy:(unichar *)characters length: numCharacters freeWhenDone: NO];
773     substituteFont.font = findSubstituteFont(renderer, string, families);
774     [string release];
775     return rendererForAlternateFont(renderer, substituteFont);
776 }
777
778 const FontData* FontData::findSubstituteFontData(const UChar* characters, unsigned numCharacters, const FontDescription& fontDescription) const
779 {
780     CREATE_FAMILY_ARRAY(fontDescription, families);
781     return findSubstituteRenderer(this, (const unichar*)characters, numCharacters, families);
782 }
783
784 // Nasty hack to determine if we should round or ceil space widths.
785 // If the font is monospace or fake monospace we ceil to ensure that 
786 // every character and the space are the same width.  Otherwise we round.
787 static bool computeWidthForSpace(FontData *renderer)
788 {
789     renderer->m_spaceGlyph = extendGlyphMap(renderer, SPACE);
790     if (renderer->m_spaceGlyph == 0)
791         return NO;
792
793     float width = renderer->widthForGlyph(renderer->m_spaceGlyph);
794
795     renderer->m_spaceWidth = width;
796
797     renderer->m_treatAsFixedPitch = [[WebTextRendererFactory sharedFactory] isFontFixedPitch:renderer->m_font];
798     renderer->m_adjustedSpaceWidth = renderer->m_treatAsFixedPitch ? ceilf(width) : roundf(width);
799     
800     return YES;
801 }
802
803 static bool setUpFont(FontData *renderer)
804 {
805     renderer->m_font.font = renderer->m_font.forPrinter ? [renderer->m_font.font printerFont] : [renderer->m_font.font screenFont];
806
807     ATSUStyle fontStyle;
808     if (ATSUCreateStyle(&fontStyle) != noErr)
809         return NO;
810
811     if (!fillStyleWithAttributes(fontStyle, renderer->m_font.font)) {
812         ATSUDisposeStyle(fontStyle);
813         return NO;
814     }
815
816     if (wkGetATSStyleGroup(fontStyle, &renderer->m_styleGroup) != noErr) {
817         ATSUDisposeStyle(fontStyle);
818         return NO;
819     }
820
821     ATSUDisposeStyle(fontStyle);
822
823     if (!computeWidthForSpace(renderer)) {
824         freeGlyphMap(renderer->m_characterToGlyphMap);
825         renderer->m_characterToGlyphMap = 0;
826         wkReleaseStyleGroup(renderer->m_styleGroup);
827         renderer->m_styleGroup = 0;
828         return NO;
829     }
830     
831     return YES;
832 }
833
834 #if !ERROR_DISABLED
835
836 static NSString *pathFromFont(NSFont *font)
837 {
838     FSSpec oFile;
839     OSStatus status = ATSFontGetFileSpecification(FMGetATSFontRefFromFont((FMFont)wkGetNSFontATSUFontId(font)), &oFile);
840     if (status == noErr) {
841         OSErr err;
842         FSRef fileRef;
843         err = FSpMakeFSRef(&oFile, &fileRef);
844         if (err == noErr) {
845             UInt8 filePathBuffer[PATH_MAX];
846             status = FSRefMakePath(&fileRef, filePathBuffer, PATH_MAX);
847             if (status == noErr)
848                 return [NSString stringWithUTF8String:(const char *)filePathBuffer];
849         }
850     }
851     return nil;
852 }
853
854 #endif
855
856 // Useful page for testing http://home.att.net/~jameskass
857 static void drawGlyphs(NSFont *font, NSColor *color, CGGlyph *glyphs, CGSize *advances, float x, float y, int numGlyphs,
858     float syntheticBoldOffset, bool syntheticOblique)
859 {
860     NSGraphicsContext *gContext = [NSGraphicsContext currentContext];
861     CGContextRef cgContext = (CGContextRef)[gContext graphicsPort];
862
863     bool originalShouldUseFontSmoothing = wkCGContextGetShouldSmoothFonts(cgContext);
864     CGContextSetShouldSmoothFonts(cgContext, WebCoreShouldUseFontSmoothing());
865     
866     NSFont *drawFont;
867     if ([gContext isDrawingToScreen]) {
868         drawFont = [font screenFont];
869         if (drawFont != font)
870             // We are getting this in too many places (3406411); use ERROR so it only prints on debug versions for now. (We should debug this also, eventually).
871             LOG_ERROR("Attempting to set non-screen font (%@) when drawing to screen.  Using screen font anyway, may result in incorrect metrics.",
872                 [[[font fontDescriptor] fontAttributes] objectForKey:NSFontNameAttribute]);
873     } else {
874         drawFont = [font printerFont];
875         if (drawFont != font)
876             NSLog(@"Attempting to set non-printer font (%@) when printing.  Using printer font anyway, may result in incorrect metrics.",
877                 [[[font fontDescriptor] fontAttributes] objectForKey:NSFontNameAttribute]);
878     }
879     
880     CGContextSetFont(cgContext, wkGetCGFontFromNSFont(drawFont));
881
882     CGAffineTransform matrix;
883     memcpy(&matrix, [drawFont matrix], sizeof(matrix));
884     if ([gContext isFlipped]) {
885         matrix.b = -matrix.b;
886         matrix.d = -matrix.d;
887     }
888     if (syntheticOblique)
889         matrix = CGAffineTransformConcat(matrix, CGAffineTransformMake(1, 0, -tanf(SYNTHETIC_OBLIQUE_ANGLE * acosf(0) / 90), 1, 0, 0)); 
890     CGContextSetTextMatrix(cgContext, matrix);
891
892     wkSetCGFontRenderingMode(cgContext, drawFont);
893     CGContextSetFontSize(cgContext, 1.0f);
894
895     [color set];
896
897     CGContextSetTextPosition(cgContext, x, y);
898     CGContextShowGlyphsWithAdvances(cgContext, glyphs, advances, numGlyphs);
899     if (syntheticBoldOffset) {
900         CGContextSetTextPosition(cgContext, x + syntheticBoldOffset, y);
901         CGContextShowGlyphsWithAdvances(cgContext, glyphs, advances, numGlyphs);
902     }
903
904     CGContextSetShouldSmoothFonts(cgContext, originalShouldUseFontSmoothing);
905 }
906
907 static void CG_drawHighlight(FontData *renderer, const WebCoreTextRun * run, const WebCoreTextStyle *style, const WebCoreTextGeometry *geometry)
908 {
909     if (run->length == 0)
910         return;
911
912     if (style->backgroundColor == nil)
913         return;
914
915     [style->backgroundColor set];
916     [NSBezierPath fillRect:CG_selectionRect(renderer, run, style, geometry)];
917 }
918
919 static NSRect CG_selectionRect(FontData *renderer, const WebCoreTextRun * run, const WebCoreTextStyle *style, const WebCoreTextGeometry *geometry)
920 {
921     float yPos = geometry->useFontMetricsForSelectionYAndHeight
922         ? geometry->point.y() - renderer->ascent() - (renderer->lineGap() / 2) : geometry->selectionY;
923     float height = geometry->useFontMetricsForSelectionYAndHeight
924         ? renderer->lineSpacing() : geometry->selectionHeight;
925
926     WebCoreTextRun completeRun = *run;
927     completeRun.from = 0;
928     completeRun.to = run->length;
929
930     WidthIterator it;
931     initializeWidthIterator(&it, renderer, &completeRun, style);
932     
933     advanceWidthIterator(&it, run->from, 0, 0, 0);
934     float beforeWidth = it.runWidthSoFar;
935     advanceWidthIterator(&it, run->to, 0, 0, 0);
936     float afterWidth = it.runWidthSoFar;
937     // Using roundf() rather than ceilf() for the right edge as a compromise to ensure correct caret positioning
938     if (style->rtl) {
939         advanceWidthIterator(&it, run->length, 0, 0, 0);
940         float totalWidth = it.runWidthSoFar;
941         return NSMakeRect(geometry->point.x() + floorf(totalWidth - afterWidth), yPos, roundf(totalWidth - beforeWidth) - floorf(totalWidth - afterWidth), height);
942     } else {
943         return NSMakeRect(geometry->point.x() + floorf(beforeWidth), yPos, roundf(afterWidth) - floorf(beforeWidth), height);
944     }
945 }
946
947 static void CG_draw(FontData *renderer, const WebCoreTextRun *run, const WebCoreTextStyle *style, const WebCoreTextGeometry *geometry)
948 {
949     float *widthBuffer, localWidthBuffer[LOCAL_BUFFER_SIZE];
950     CGGlyph *glyphBuffer, localGlyphBuffer[LOCAL_BUFFER_SIZE];
951     FontData **rendererBuffer, *localRendererBuffer[LOCAL_BUFFER_SIZE];
952     CGSize *advances, localAdvanceBuffer[LOCAL_BUFFER_SIZE];
953     int numGlyphs = 0, i;
954     float startX;
955     unsigned length = run->length;
956     
957     if (run->length == 0)
958         return;
959
960     if (length * MAX_GLYPH_EXPANSION > LOCAL_BUFFER_SIZE) {
961         advances = new CGSize[length * MAX_GLYPH_EXPANSION];
962         widthBuffer = new float[length * MAX_GLYPH_EXPANSION];
963         glyphBuffer = new CGGlyph[length * MAX_GLYPH_EXPANSION];
964         rendererBuffer = new FontData*[length * MAX_GLYPH_EXPANSION];
965     } else {
966         advances = localAdvanceBuffer;
967         widthBuffer = localWidthBuffer;
968         glyphBuffer = localGlyphBuffer;
969         rendererBuffer = localRendererBuffer;
970     }
971
972     CG_floatWidthForRun(renderer, run, style, widthBuffer, rendererBuffer, glyphBuffer, &startX, &numGlyphs);
973         
974     // Eek.  We couldn't generate ANY glyphs for the run.
975     if (numGlyphs <= 0)
976         return;
977         
978     // Fill the advances array.
979     for (i = 0; i < numGlyphs; i++) {
980         advances[i].width = widthBuffer[i];
981         advances[i].height = 0;
982     }
983
984     // Calculate the starting point of the glyphs to be displayed by adding
985     // all the advances up to the first glyph.
986     startX += geometry->point.x();
987
988     if (style->backgroundColor != nil)
989         CG_drawHighlight(renderer, run, style, geometry);
990     
991     // Swap the order of the glyphs if right-to-left.
992     if (style->rtl) {
993         int i;
994         int mid = numGlyphs / 2;
995         int end;
996         for (i = 0, end = numGlyphs - 1; i < mid; ++i, --end) {
997             CGGlyph gswap1 = glyphBuffer[i];
998             CGGlyph gswap2 = glyphBuffer[end];
999             glyphBuffer[i] = gswap2;
1000             glyphBuffer[end] = gswap1;
1001
1002             CGSize aswap1 = advances[i];
1003             CGSize aswap2 = advances[end];
1004             advances[i] = aswap2;
1005             advances[end] = aswap1;
1006
1007             FontData *rswap1 = rendererBuffer[i];
1008             FontData *rswap2 = rendererBuffer[end];
1009             rendererBuffer[i] = rswap2;
1010             rendererBuffer[end] = rswap1;
1011         }
1012     }
1013
1014     // Draw each contiguous run of glyphs that use the same renderer.
1015     FontData *currentRenderer = rendererBuffer[0];
1016     float nextX = startX;
1017     int lastFrom = 0;
1018     int nextGlyph = 0;
1019     while (nextGlyph < numGlyphs) {
1020         FontData *nextRenderer = rendererBuffer[nextGlyph];
1021         if (nextRenderer != currentRenderer) {
1022             drawGlyphs(currentRenderer->m_font.font, style->textColor, &glyphBuffer[lastFrom], &advances[lastFrom],
1023                 startX, geometry->point.y(), nextGlyph - lastFrom,
1024                 currentRenderer->m_syntheticBoldOffset, currentRenderer->m_font.syntheticOblique);
1025             lastFrom = nextGlyph;
1026             currentRenderer = nextRenderer;
1027             startX = nextX;
1028         }
1029         nextX += advances[nextGlyph].width;
1030         nextGlyph++;
1031     }
1032     drawGlyphs(currentRenderer->m_font.font, style->textColor, &glyphBuffer[lastFrom], &advances[lastFrom],
1033         startX, geometry->point.y(), nextGlyph - lastFrom,
1034         currentRenderer->m_syntheticBoldOffset, currentRenderer->m_font.syntheticOblique);
1035
1036     if (advances != localAdvanceBuffer) {
1037         delete []advances;
1038         delete []widthBuffer;
1039         delete []glyphBuffer;
1040         delete []rendererBuffer;
1041     }
1042 }
1043
1044 static float CG_floatWidthForRun(FontData *renderer, const WebCoreTextRun *run, const WebCoreTextStyle *style, float *widthBuffer, FontData **rendererBuffer, CGGlyph *glyphBuffer, float *startPosition, int *numGlyphsResult)
1045 {
1046     WidthIterator it;
1047     WebCoreTextRun completeRun;
1048     const WebCoreTextRun *aRun;
1049     if (!style->rtl)
1050         aRun = run;
1051     else {
1052         completeRun = *run;
1053         completeRun.to = run->length;
1054         aRun = &completeRun;
1055     }
1056     initializeWidthIterator(&it, renderer, aRun, style);
1057     int numGlyphs = advanceWidthIterator(&it, run->to, widthBuffer, rendererBuffer, glyphBuffer);
1058     float runWidth = it.runWidthSoFar;
1059     if (startPosition) {
1060         if (!style->rtl)
1061             *startPosition = it.widthToStart;
1062         else {
1063             float finalRoundingWidth = it.finalRoundingWidth;
1064             advanceWidthIterator(&it, run->length, 0, 0, 0);
1065             *startPosition = it.runWidthSoFar - runWidth + finalRoundingWidth;
1066         }
1067     }
1068     if (numGlyphsResult)
1069         *numGlyphsResult = numGlyphs;
1070     return runWidth;
1071 }
1072
1073 void FontData::updateGlyphMapEntry(UChar c, ATSGlyphRef glyph, const FontData *substituteRenderer) const
1074 {
1075     GlyphMap *map;
1076     for (map = m_characterToGlyphMap; map; map = map->next) {
1077         UChar32 start = map->startRange;
1078         if (c >= start && c <= map->endRange) {
1079             int i = c - start;
1080             map->glyphs[i].glyph = glyph;
1081             // This renderer will leak.
1082             // No problem though; we want it to stick around forever.
1083             // Max theoretical retain counts applied here will be num_fonts_on_system * num_glyphs_in_font.
1084             map->glyphs[i].renderer = substituteRenderer;
1085             break;
1086         }
1087     }
1088 }
1089
1090 static ATSGlyphRef extendGlyphMap(const FontData *renderer, UChar32 c)
1091 {
1092     GlyphMap *map = new GlyphMap;
1093     ATSLayoutRecord *glyphRecord;
1094     char glyphVector[WKGlyphVectorSize];
1095     UChar32 end, start;
1096     unsigned blockSize;
1097     
1098     if (renderer->m_characterToGlyphMap == 0)
1099         blockSize = INITIAL_BLOCK_SIZE;
1100     else
1101         blockSize = INCREMENTAL_BLOCK_SIZE;
1102     start = (c / blockSize) * blockSize;
1103     end = start + (blockSize - 1);
1104
1105     map->startRange = start;
1106     map->endRange = end;
1107     map->next = 0;
1108     
1109     unsigned i;
1110     unsigned count = end - start + 1;
1111     unsigned short buffer[INCREMENTAL_BLOCK_SIZE * 2 + 2];
1112     unsigned bufferLength;
1113
1114     if (start < 0x10000) {
1115         bufferLength = count;
1116         for (i = 0; i < count; i++)
1117             buffer[i] = i + start;
1118
1119         if (start == 0) {
1120             // Control characters must not render at all.
1121             for (i = 0; i < 0x20; ++i)
1122                 buffer[i] = ZERO_WIDTH_SPACE;
1123             buffer[0x7F] = ZERO_WIDTH_SPACE;
1124
1125             // But \n, \t, and nonbreaking space must render as a space.
1126             buffer[(int)'\n'] = ' ';
1127             buffer[(int)'\t'] = ' ';
1128             buffer[NO_BREAK_SPACE] = ' ';
1129         }
1130     } else {
1131         bufferLength = count * 2;
1132         for (i = 0; i < count; i++) {
1133             int c = i + start;
1134             buffer[i * 2] = U16_LEAD(c);
1135             buffer[i * 2 + 1] = U16_TRAIL(c);
1136         }
1137     }
1138
1139     OSStatus status = wkInitializeGlyphVector(count, &glyphVector);
1140     if (status != noErr) {
1141         // This should never happen, perhaps indicates a bad font!  If it does the
1142         // font substitution code will find an alternate font.
1143         delete map;
1144         return 0;
1145     }
1146
1147     wkConvertCharToGlyphs(renderer->m_styleGroup, &buffer[0], bufferLength, &glyphVector);
1148     unsigned numGlyphs = wkGetGlyphVectorNumGlyphs(&glyphVector);
1149     if (numGlyphs != count) {
1150         // This should never happen, perhaps indicates a bad font?
1151         // If it does happen, the font substitution code will find an alternate font.
1152         wkClearGlyphVector(&glyphVector);
1153         delete map;
1154         return 0;
1155     }
1156
1157     map->glyphs = new GlyphEntry[count];
1158     glyphRecord = (ATSLayoutRecord *)wkGetGlyphVectorFirstRecord(glyphVector);
1159     for (i = 0; i < count; i++) {
1160         map->glyphs[i].glyph = glyphRecord->glyphID;
1161         map->glyphs[i].renderer = renderer;
1162         glyphRecord = (ATSLayoutRecord *)((char *)glyphRecord + wkGetGlyphVectorRecordSize(glyphVector));
1163     }
1164     wkClearGlyphVector(&glyphVector);
1165     
1166     if (renderer->m_characterToGlyphMap == 0)
1167         renderer->m_characterToGlyphMap = map;
1168     else {
1169         GlyphMap *lastMap = renderer->m_characterToGlyphMap;
1170         while (lastMap->next != 0)
1171             lastMap = lastMap->next;
1172         lastMap->next = map;
1173     }
1174
1175     ATSGlyphRef glyph = map->glyphs[c - start].glyph;
1176
1177     // Special case for characters 007F-00A0.
1178     if (glyph == 0 && c >= 0x7F && c <= 0xA0) {
1179         glyph = wkGetDefaultGlyphForChar(renderer->m_font.font, c);
1180         map->glyphs[c - start].glyph = glyph;
1181     }
1182
1183     return glyph;
1184 }
1185
1186 static WidthMap *extendWidthMap(const FontData *renderer, ATSGlyphRef glyph)
1187 {
1188     WidthMap *map = new WidthMap;
1189     unsigned end;
1190     ATSGlyphRef start;
1191     unsigned blockSize;
1192     unsigned i, count;
1193     
1194     NSFont *f = renderer->m_font.font;
1195     if (renderer->m_glyphToWidthMap == 0) {
1196         if ([f numberOfGlyphs] < INITIAL_BLOCK_SIZE)
1197             blockSize = [f numberOfGlyphs];
1198          else
1199             blockSize = INITIAL_BLOCK_SIZE;
1200     } else {
1201         blockSize = INCREMENTAL_BLOCK_SIZE;
1202     }
1203     if (blockSize == 0) {
1204         start = 0;
1205     } else {
1206         start = (glyph / blockSize) * blockSize;
1207     }
1208     end = ((unsigned)start) + blockSize; 
1209
1210     map->startRange = start;
1211     map->endRange = end;
1212     count = end - start + 1;
1213
1214     map->widths = new WebGlyphWidth[count];
1215     for (i = 0; i < count; i++)
1216         map->widths[i] = NAN;
1217
1218     if (renderer->m_glyphToWidthMap == 0)
1219         renderer->m_glyphToWidthMap = map;
1220     else {
1221         WidthMap *lastMap = renderer->m_glyphToWidthMap;
1222         while (lastMap->next != 0)
1223             lastMap = lastMap->next;
1224         lastMap->next = map;
1225     }
1226
1227     return map;
1228 }
1229
1230 static void initializeATSUStyle(FontData *renderer)
1231 {
1232     // The two NSFont calls in this method (pointSize and _atsFontID) do not raise exceptions.
1233
1234     if (!renderer->m_ATSUStyleInitialized) {
1235         OSStatus status;
1236         ByteCount propTableSize;
1237         
1238         status = ATSUCreateStyle(&renderer->m_ATSUStyle);
1239         if (status != noErr)
1240             LOG_ERROR("ATSUCreateStyle failed (%d)", status);
1241     
1242         ATSUFontID fontID = wkGetNSFontATSUFontId(renderer->m_font.font);
1243         if (fontID == 0) {
1244             ATSUDisposeStyle(renderer->m_ATSUStyle);
1245             LOG_ERROR("unable to get ATSUFontID for %@", renderer->m_font.font);
1246             return;
1247         }
1248         
1249         CGAffineTransform transform = CGAffineTransformMakeScale(1, -1);
1250         if (renderer->m_font.syntheticOblique)
1251             transform = CGAffineTransformConcat(transform, CGAffineTransformMake(1, 0, -tanf(SYNTHETIC_OBLIQUE_ANGLE * acosf(0) / 90), 1, 0, 0)); 
1252         Fixed fontSize = FloatToFixed([renderer->m_font.font pointSize]);
1253         // Turn off automatic kerning until it is supported in the CG code path (6136 in bugzilla)
1254         Fract kerningInhibitFactor = FloatToFract(1.0);
1255         ATSUAttributeTag styleTags[4] = { kATSUSizeTag, kATSUFontTag, kATSUFontMatrixTag, kATSUKerningInhibitFactorTag };
1256         ByteCount styleSizes[4] = { sizeof(Fixed), sizeof(ATSUFontID), sizeof(CGAffineTransform), sizeof(Fract) };
1257         ATSUAttributeValuePtr styleValues[4] = { &fontSize, &fontID, &transform, &kerningInhibitFactor };
1258         status = ATSUSetAttributes(renderer->m_ATSUStyle, 4, styleTags, styleSizes, styleValues);
1259         if (status != noErr)
1260             LOG_ERROR("ATSUSetAttributes failed (%d)", status);
1261         status = ATSFontGetTable(fontID, 'prop', 0, 0, 0, &propTableSize);
1262         if (status == noErr)    // naively assume that if a 'prop' table exists then it contains mirroring info
1263             renderer->m_ATSUMirrors = true;
1264         else if (status == kATSInvalidFontTableAccess)
1265             renderer->m_ATSUMirrors = false;
1266         else
1267             LOG_ERROR("ATSFontGetTable failed (%d)", status);
1268
1269         // Turn off ligatures such as 'fi' to match the CG code path's behavior, until bugzilla 6135 is fixed.
1270         // Don't be too aggressive: if the font doesn't contain 'a', then assume that any ligatures it contains are
1271         // in characters that always go through ATSUI, and therefore allow them. Geeza Pro is an example.
1272         // See bugzilla 5166.
1273         if ([[renderer->m_font.font coveredCharacterSet] characterIsMember:'a']) {
1274             ATSUFontFeatureType featureTypes[] = { kLigaturesType };
1275             ATSUFontFeatureSelector featureSelectors[] = { kCommonLigaturesOffSelector };
1276             status = ATSUSetFontFeatures(renderer->m_ATSUStyle, 1, featureTypes, featureSelectors);
1277         }
1278
1279         renderer->m_ATSUStyleInitialized = true;
1280     }
1281 }
1282
1283 static void createATSULayoutParameters(ATSULayoutParameters *params, FontData *renderer, const WebCoreTextRun *run, const WebCoreTextStyle *style)
1284 {
1285     params->run = run;
1286     params->style = style;
1287     // FIXME: It is probably best to always allocate a buffer for RTL, since even if for this
1288     // renderer ATSUMirrors is true, for a substitute renderer it might be false.
1289     FontData** renderers = new FontData*[run->length];
1290     params->renderers = renderers;
1291     UniChar *charBuffer = (UniChar*)((style->smallCaps || (style->rtl && !renderer->m_ATSUMirrors)) ? new UniChar[run->length] : 0);
1292     params->charBuffer = charBuffer;
1293     params->syntheticBoldPass = false;
1294
1295     // The only Cocoa calls here are to NSGraphicsContext, which does not raise exceptions.
1296
1297     ATSUTextLayout layout;
1298     OSStatus status;
1299     ATSULayoutOperationOverrideSpecifier overrideSpecifier;
1300     
1301     initializeATSUStyle(renderer);
1302     
1303     // FIXME: This is currently missing the following required features that the CoreGraphics code path has:
1304     // - \n, \t, and nonbreaking space render as a space.
1305     // - Other control characters do not render (other code path uses zero-width spaces).
1306
1307     UniCharCount totalLength = run->length;
1308     UniCharArrayOffset runTo = (run->to == -1 ? totalLength : (unsigned int)run->to);
1309     UniCharArrayOffset runFrom = run->from;
1310     
1311     if (charBuffer)
1312         memcpy(charBuffer, run->characters, totalLength * sizeof(UniChar));
1313
1314     UniCharCount runLength = runTo - runFrom;
1315     
1316     status = ATSUCreateTextLayoutWithTextPtr(
1317             (charBuffer ? charBuffer : run->characters),
1318             runFrom,        // offset
1319             runLength,      // length
1320             totalLength,    // total length
1321             1,              // styleRunCount
1322             &runLength,     // length of style run
1323             &renderer->m_ATSUStyle, 
1324             &layout);
1325     if (status != noErr)
1326         LOG_ERROR("ATSUCreateTextLayoutWithTextPtr failed(%d)", status);
1327     params->layout = layout;
1328     ATSUSetTextLayoutRefCon(layout, (UInt32)params);
1329
1330     CGContextRef cgContext = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
1331     ATSLineLayoutOptions lineLayoutOptions = kATSLineKeepSpacesOutOfMargin | kATSLineHasNoHangers;
1332     Boolean rtl = style->rtl;
1333     overrideSpecifier.operationSelector = kATSULayoutOperationPostLayoutAdjustment;
1334     overrideSpecifier.overrideUPP = overrideLayoutOperation;
1335     ATSUAttributeTag tags[] = { kATSUCGContextTag, kATSULineLayoutOptionsTag, kATSULineDirectionTag, kATSULayoutOperationOverrideTag };
1336     ByteCount sizes[] = { sizeof(CGContextRef), sizeof(ATSLineLayoutOptions), sizeof(Boolean), sizeof(ATSULayoutOperationOverrideSpecifier) };
1337     ATSUAttributeValuePtr values[] = { &cgContext, &lineLayoutOptions, &rtl, &overrideSpecifier };
1338     
1339     status = ATSUSetLayoutControls(layout, (style->applyWordRounding ? 4 : 3), tags, sizes, values);
1340     if (status != noErr)
1341         LOG_ERROR("ATSUSetLayoutControls failed(%d)", status);
1342
1343     status = ATSUSetTransientFontMatching(layout, YES);
1344     if (status != noErr)
1345         LOG_ERROR("ATSUSetTransientFontMatching failed(%d)", status);
1346
1347     params->hasSyntheticBold = false;
1348     ATSUFontID ATSUSubstituteFont;
1349     UniCharArrayOffset substituteOffset = runFrom;
1350     UniCharCount substituteLength;
1351     UniCharArrayOffset lastOffset;
1352     FontData *substituteRenderer = 0;
1353
1354     while (substituteOffset < runTo) {
1355         lastOffset = substituteOffset;
1356         status = ATSUMatchFontsToText(layout, substituteOffset, kATSUToTextEnd, &ATSUSubstituteFont, &substituteOffset, &substituteLength);
1357         if (status == kATSUFontsMatched || status == kATSUFontsNotMatched) {
1358             substituteRenderer = (FontData*)findSubstituteRenderer(renderer, run->characters+substituteOffset, substituteLength, style->families);
1359             if (substituteRenderer) {
1360                 initializeATSUStyle(substituteRenderer);
1361                 if (substituteRenderer->m_ATSUStyle)
1362                     ATSUSetRunStyle(layout, substituteRenderer->m_ATSUStyle, substituteOffset, substituteLength);
1363             } else
1364                 substituteRenderer = renderer;
1365         } else {
1366             substituteOffset = runTo;
1367             substituteLength = 0;
1368         }
1369
1370         bool isSmallCap = false;
1371         UniCharArrayOffset firstSmallCap = 0;
1372         FontData *r = renderer;
1373         UniCharArrayOffset i;
1374         for (i = lastOffset;  ; i++) {
1375             if (i == substituteOffset || i == substituteOffset + substituteLength) {
1376                 if (isSmallCap) {
1377                     isSmallCap = false;
1378                     initializeATSUStyle(r->smallCapsFontData());
1379                     ATSUSetRunStyle(layout, r->smallCapsFontData()->m_ATSUStyle, firstSmallCap, i - firstSmallCap);
1380                 }
1381                 if (i == substituteOffset && substituteLength > 0)
1382                     r = substituteRenderer;
1383                 else
1384                     break;
1385             }
1386             if (rtl && charBuffer && !r->m_ATSUMirrors)
1387                 charBuffer[i] = u_charMirror(charBuffer[i]);
1388             if (style->smallCaps) {
1389                 UniChar c = charBuffer[i];
1390                 UniChar newC;
1391                 if (U_GET_GC_MASK(c) & U_GC_M_MASK)
1392                     renderers[i] = isSmallCap ? r->smallCapsFontData() : r;
1393                 else if (!u_isUUppercase(c) && (newC = u_toupper(c)) != c) {
1394                     charBuffer[i] = newC;
1395                     if (!isSmallCap) {
1396                         isSmallCap = true;
1397                         firstSmallCap = i;
1398                     }
1399                     renderers[i] = r->smallCapsFontData();
1400                 } else {
1401                     if (isSmallCap) {
1402                         isSmallCap = false;
1403                         initializeATSUStyle(r->smallCapsFontData());
1404                         ATSUSetRunStyle(layout, r->smallCapsFontData()->m_ATSUStyle, firstSmallCap, i - firstSmallCap);
1405                     }
1406                     renderers[i] = r;
1407                 }
1408             } else
1409                 renderers[i] = r;
1410             if (renderers[i]->m_syntheticBoldOffset)
1411                 params->hasSyntheticBold = true;
1412         }
1413         substituteOffset += substituteLength;
1414     }
1415     if (style->padding) {
1416         float numSpaces = 0;
1417         unsigned k;
1418         for (k = 0; k < totalLength; k++)
1419             if (isSpace(run->characters[k]))
1420                 numSpaces++;
1421
1422         params->padPerSpace = ceilf(style->padding / numSpaces);
1423     } else
1424         params->padPerSpace = 0;
1425 }
1426
1427 static void disposeATSULayoutParameters(ATSULayoutParameters *params)
1428 {
1429     ATSUDisposeTextLayout(params->layout);
1430     delete []params->charBuffer;
1431     delete []params->renderers;
1432 }
1433
1434 static ATSTrapezoid getTextBounds(FontData *renderer, const WebCoreTextRun *run, const WebCoreTextStyle *style, NSPoint p)
1435 {
1436     OSStatus status;
1437     
1438     if (run->to - run->from <= 0) {
1439         ATSTrapezoid nilTrapezoid = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
1440         return nilTrapezoid;
1441     }
1442
1443     ATSULayoutParameters params;
1444     createATSULayoutParameters(&params, renderer, run, style);
1445
1446     ATSTrapezoid firstGlyphBounds;
1447     ItemCount actualNumBounds;
1448     status = ATSUGetGlyphBounds(params.layout, FloatToFixed(p.x), FloatToFixed(p.y), run->from, run->to - run->from, kATSUseFractionalOrigins, 1, &firstGlyphBounds, &actualNumBounds);    
1449     if (status != noErr)
1450         LOG_ERROR("ATSUGetGlyphBounds() failed(%d)", status);
1451     if (actualNumBounds != 1)
1452         LOG_ERROR("unexpected result from ATSUGetGlyphBounds(): actualNumBounds(%d) != 1", actualNumBounds);
1453
1454     disposeATSULayoutParameters(&params);
1455
1456     return firstGlyphBounds;
1457 }
1458
1459 static float ATSU_floatWidthForRun(FontData *renderer, const WebCoreTextRun *run, const WebCoreTextStyle *style)
1460 {
1461     ATSTrapezoid oGlyphBounds = getTextBounds(renderer, run, style, NSZeroPoint);
1462     return MAX(FixedToFloat(oGlyphBounds.upperRight.x), FixedToFloat(oGlyphBounds.lowerRight.x)) -
1463         MIN(FixedToFloat(oGlyphBounds.upperLeft.x), FixedToFloat(oGlyphBounds.lowerLeft.x));
1464 }
1465
1466 // Be sure to free the run.characters allocated by this function.
1467 static WebCoreTextRun addDirectionalOverride(const WebCoreTextRun *run, bool rtl)
1468 {
1469     int from = run->from;
1470     int to = run->to;
1471     if (from == -1)
1472         from = 0;
1473     if (to == -1)
1474         to = run->length;
1475
1476     UniChar *charactersWithOverride = new UniChar[run->length + 2];
1477
1478     charactersWithOverride[0] = rtl ? RIGHT_TO_LEFT_OVERRIDE : LEFT_TO_RIGHT_OVERRIDE;
1479     memcpy(&charactersWithOverride[1], &run->characters[0], sizeof(UniChar) * run->length);
1480     charactersWithOverride[run->length + 1] = POP_DIRECTIONAL_FORMATTING;
1481
1482     WebCoreTextRun runWithOverride;
1483
1484     runWithOverride.from = from + 1;
1485     runWithOverride.to = to + 1;
1486     runWithOverride.length = run->length + 2;
1487     runWithOverride.characters = charactersWithOverride;
1488
1489     return runWithOverride;
1490 }
1491
1492 static void ATSU_drawHighlight(FontData *renderer, const WebCoreTextRun *run, const WebCoreTextStyle *style, const WebCoreTextGeometry *geometry)
1493 {
1494     // The only Cocoa calls made here are to NSColor and NSBezierPath, and they do not raise exceptions.
1495
1496     if (style->backgroundColor == nil)
1497         return;
1498     if (run->to <= run->from)
1499         return;
1500     
1501     [style->backgroundColor set];
1502     [NSBezierPath fillRect:ATSU_selectionRect(renderer, run, style, geometry)];
1503 }
1504
1505 static NSRect ATSU_selectionRect(FontData *renderer, const WebCoreTextRun *run, const WebCoreTextStyle *style, const WebCoreTextGeometry *geometry)
1506 {
1507     int from = run->from;
1508     int to = run->to;
1509     if (from == -1)
1510         from = 0;
1511     if (to == -1)
1512         to = run->length;
1513         
1514     WebCoreTextRun completeRun = *run;
1515     completeRun.from = 0;
1516     completeRun.to = run->length;
1517     
1518     WebCoreTextRun *aRun = &completeRun;
1519     WebCoreTextRun swappedRun;
1520     
1521     if (style->directionalOverride) {
1522         swappedRun = addDirectionalOverride(aRun, style->rtl);
1523         aRun = &swappedRun;
1524         from++;
1525         to++;
1526     }
1527    
1528     ATSULayoutParameters params;
1529     createATSULayoutParameters(&params, renderer, aRun, style);
1530     
1531     ATSTrapezoid firstGlyphBounds;
1532     ItemCount actualNumBounds;
1533     
1534     OSStatus status = ATSUGetGlyphBounds(params.layout, 0, 0, from, to - from, kATSUseFractionalOrigins, 1, &firstGlyphBounds, &actualNumBounds);
1535     if (status != noErr || actualNumBounds != 1) {
1536         static ATSTrapezoid zeroTrapezoid = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
1537         firstGlyphBounds = zeroTrapezoid;
1538     }
1539     disposeATSULayoutParameters(&params);    
1540     
1541     float beforeWidth = MIN(FixedToFloat(firstGlyphBounds.lowerLeft.x), FixedToFloat(firstGlyphBounds.upperLeft.x));
1542     float afterWidth = MAX(FixedToFloat(firstGlyphBounds.lowerRight.x), FixedToFloat(firstGlyphBounds.upperRight.x));
1543     float yPos = geometry->useFontMetricsForSelectionYAndHeight
1544         ? geometry->point.y() - renderer->ascent() : geometry->selectionY;
1545     float height = geometry->useFontMetricsForSelectionYAndHeight
1546         ? renderer->lineSpacing() : geometry->selectionHeight;
1547
1548     NSRect rect = NSMakeRect(geometry->point.x() + floorf(beforeWidth), yPos, roundf(afterWidth) - floorf(beforeWidth), height);
1549
1550     if (style->directionalOverride)
1551         delete []swappedRun.characters;
1552
1553     return rect;
1554 }
1555
1556
1557 static void ATSU_draw(FontData *renderer, const WebCoreTextRun *run, const WebCoreTextStyle *style, const WebCoreTextGeometry *geometry)
1558 {
1559     // The only Cocoa calls made here are to NSColor and NSGraphicsContext, and they do not raise exceptions.
1560
1561     OSStatus status;
1562     int from, to;
1563     const WebCoreTextRun *aRun = run;
1564     WebCoreTextRun swappedRun;
1565     
1566     if (style->directionalOverride) {
1567         swappedRun = addDirectionalOverride(run, style->rtl);
1568         aRun = &swappedRun;
1569     }
1570
1571     from = aRun->from;
1572     to = aRun->to;
1573     if (from == -1)
1574         from = 0;
1575     if (to == -1)
1576         to = run->length;
1577
1578     int runLength = to - from;
1579     if (runLength <= 0)
1580         return;
1581
1582     WebCoreTextRun completeRun = *aRun;
1583     completeRun.from = 0;
1584     completeRun.to = aRun->length;
1585     ATSULayoutParameters params;
1586     createATSULayoutParameters(&params, renderer, &completeRun, style);
1587
1588     if (style->backgroundColor != nil)
1589         ATSU_drawHighlight(renderer, run, style, geometry);
1590
1591     [style->textColor set];
1592
1593     // ATSUI can't draw beyond -32768 to +32767 so we translate the CTM and tell ATSUI to draw at (0, 0).
1594     NSGraphicsContext *gContext = [NSGraphicsContext currentContext];
1595     CGContextRef context = (CGContextRef)[gContext graphicsPort];
1596     CGContextTranslateCTM(context, geometry->point.x(), geometry->point.y());
1597     bool flipped = [gContext isFlipped];
1598     if (!flipped)
1599         CGContextScaleCTM(context, 1.0, -1.0);
1600     status = ATSUDrawText(params.layout, aRun->from, runLength, 0, 0);
1601     if (status == noErr && params.hasSyntheticBold) {
1602         // Force relayout for the bold pass
1603         ATSUClearLayoutCache(params.layout, 0);
1604         params.syntheticBoldPass = true;
1605         status = ATSUDrawText(params.layout, aRun->from, runLength, 0, 0);
1606     }
1607     if (!flipped)
1608         CGContextScaleCTM(context, 1.0, -1.0);
1609     CGContextTranslateCTM(context, -geometry->point.x(), -geometry->point.y());
1610
1611     if (status != noErr) {
1612         // Nothing to do but report the error (dev build only).
1613         LOG_ERROR("ATSUDrawText() failed(%d)", status);
1614     }
1615
1616     disposeATSULayoutParameters(&params);
1617     
1618     if (style->directionalOverride)
1619         delete []swappedRun.characters;
1620 }
1621
1622 static int ATSU_pointToOffset(FontData *renderer, const WebCoreTextRun *run, const WebCoreTextStyle *style,
1623     int x, bool includePartialGlyphs)
1624 {
1625     const WebCoreTextRun *aRun = run;
1626     WebCoreTextRun swappedRun;
1627     
1628     // Enclose in LRO/RLO - PDF to force ATSU to render visually.
1629     if (style->directionalOverride) {
1630         swappedRun = addDirectionalOverride(aRun, style->rtl);
1631         aRun = &swappedRun;
1632     }
1633
1634     ATSULayoutParameters params;
1635     createATSULayoutParameters(&params, renderer, aRun, style);
1636
1637     UniCharArrayOffset primaryOffset = aRun->from;
1638     
1639     // FIXME: No idea how to avoid including partial glyphs.
1640     // Not even sure if that's the behavior this yields now.
1641     Boolean isLeading;
1642     UniCharArrayOffset secondaryOffset = 0;
1643     OSStatus status = ATSUPositionToOffset(params.layout, FloatToFixed(x), FloatToFixed(-1), &primaryOffset, &isLeading, &secondaryOffset);
1644     unsigned offset;
1645     if (status == noErr) {
1646         offset = (unsigned)primaryOffset;
1647     } else {
1648         // Failed to find offset!  Return 0 offset.
1649         offset = 0;
1650     }
1651
1652     disposeATSULayoutParameters(&params);
1653     
1654     if (style->directionalOverride)
1655         delete []swappedRun.characters;
1656
1657     return offset - aRun->from;
1658 }
1659
1660 static bool advanceWidthIteratorOneCharacter(WidthIterator *iterator, float *totalWidth)
1661 {
1662     float widths[MAX_GLYPH_EXPANSION];
1663     FontData *renderers[MAX_GLYPH_EXPANSION];
1664     ATSGlyphRef glyphs[MAX_GLYPH_EXPANSION];            
1665     unsigned numGlyphs = advanceWidthIterator(iterator, iterator->currentCharacter + 1, widths, renderers, glyphs);
1666     unsigned i;
1667     float w = 0;
1668     for (i = 0; i < numGlyphs; ++i)
1669         w += widths[i];
1670     *totalWidth = w;
1671     return numGlyphs != 0;
1672 }
1673
1674 static int CG_pointToOffset(FontData *renderer, const WebCoreTextRun * run, const WebCoreTextStyle *style,
1675     int x, bool includePartialGlyphs)
1676 {
1677     float delta = (float)x;
1678
1679     WidthIterator it;    
1680     initializeWidthIterator(&it, renderer, run, style);
1681
1682     unsigned offset;
1683
1684     if (style->rtl) {
1685         delta -= CG_floatWidthForRun(renderer, run, style, 0, 0, 0, 0, 0);
1686         while (1) {
1687             offset = it.currentCharacter;
1688             float w;
1689             if (!advanceWidthIteratorOneCharacter(&it, &w))
1690                 break;
1691             delta += w;
1692             if (includePartialGlyphs) {
1693                 if (delta - w / 2 >= 0)
1694                     break;
1695             } else {
1696                 if (delta >= 0)
1697                     break;
1698             }
1699         }
1700     } else {
1701         while (1) {
1702             offset = it.currentCharacter;
1703             float w;
1704             if (!advanceWidthIteratorOneCharacter(&it, &w))
1705                 break;
1706             delta -= w;
1707             if (includePartialGlyphs) {
1708                 if (delta + w / 2 <= 0)
1709                     break;
1710             } else {
1711                 if (delta <= 0)
1712                     break;
1713             }
1714         }
1715     }
1716
1717     return offset - run->from;
1718 }
1719
1720 static void freeWidthMap(WidthMap *map)
1721 {
1722     while (map) {
1723         WidthMap *next = map->next;
1724         delete []map->widths;
1725         delete map;
1726         map = next;
1727     }
1728 }
1729
1730 static void freeGlyphMap(GlyphMap *map)
1731 {
1732     while (map) {
1733         GlyphMap *next = map->next;
1734         delete []map->glyphs;
1735         delete map;
1736         map = next;
1737     }
1738 }
1739
1740 Glyph FontData::glyphForCharacter(const FontData **renderer, unsigned c) const
1741 {
1742     // this loop is hot, so it is written to avoid LSU stalls
1743     GlyphMap *map;
1744     GlyphMap *nextMap;
1745     for (map = (*renderer)->m_characterToGlyphMap; map; map = nextMap) {
1746         UChar start = map->startRange;
1747         nextMap = map->next;
1748         if (c >= start && c <= map->endRange) {
1749             GlyphEntry *ge = &map->glyphs[c - start];
1750             *renderer = ge->renderer;
1751             return ge->glyph;
1752         }
1753     }
1754
1755     return extendGlyphMap(*renderer, c);
1756 }
1757
1758 static void initializeWidthIterator(WidthIterator *iterator, FontData *renderer, const WebCoreTextRun *run, const WebCoreTextStyle *style) 
1759 {
1760     iterator->renderer = renderer;
1761     iterator->run = run;
1762     iterator->style = style;
1763     iterator->currentCharacter = run->from;
1764     iterator->runWidthSoFar = 0;
1765     iterator->finalRoundingWidth = 0;
1766
1767     // If the padding is non-zero, count the number of spaces in the run
1768     // and divide that by the padding for per space addition.
1769     if (!style->padding) {
1770         iterator->padding = 0;
1771         iterator->padPerSpace = 0;
1772     } else {
1773         float numSpaces = 0;
1774         int k;
1775         for (k = run->from; k < run->to; k++)
1776             if (isSpace(run->characters[k]))
1777                 numSpaces++;
1778
1779         iterator->padding = style->padding;
1780         iterator->padPerSpace = ceilf(iterator->padding / numSpaces);
1781     }
1782     
1783     // Calculate width up to starting position of the run.  This is
1784     // necessary to ensure that our rounding hacks are always consistently
1785     // applied.
1786     if (run->from == 0) {
1787         iterator->widthToStart = 0;
1788     } else {
1789         WebCoreTextRun startPositionRun = *run;
1790         startPositionRun.from = 0;
1791         startPositionRun.to = run->length;
1792         WidthIterator startPositionIterator;
1793         initializeWidthIterator(&startPositionIterator, renderer, &startPositionRun, style);
1794         advanceWidthIterator(&startPositionIterator, run->from, 0, 0, 0);
1795         iterator->widthToStart = startPositionIterator.runWidthSoFar;
1796     }
1797 }
1798
1799 static UChar32 normalizeVoicingMarks(WidthIterator *iterator)
1800 {
1801     unsigned currentCharacter = iterator->currentCharacter;
1802     const WebCoreTextRun *run = iterator->run;
1803     if (currentCharacter + 1 < (unsigned)run->to) {
1804         if (u_getCombiningClass(run->characters[currentCharacter + 1]) == HIRAGANA_KATAKANA_VOICING_MARKS) {
1805             // Normalize into composed form using 3.2 rules.
1806             UChar normalizedCharacters[2] = { 0, 0 };
1807             UErrorCode uStatus = (UErrorCode)0;                
1808             int32_t resultLength = unorm_normalize(&run->characters[currentCharacter], 2,
1809                 UNORM_NFC, UNORM_UNICODE_3_2, &normalizedCharacters[0], 2, &uStatus);
1810             if (resultLength == 1 && uStatus == 0)
1811                 return normalizedCharacters[0];
1812         }
1813     }
1814     return 0;
1815 }
1816
1817 static unsigned advanceWidthIterator(WidthIterator *iterator, unsigned offset, float *widths, FontData **renderersUsed, ATSGlyphRef *glyphsUsed)
1818 {
1819     const WebCoreTextRun *run = iterator->run;
1820     if (offset > (unsigned)run->to)
1821         offset = run->to;
1822
1823     unsigned numGlyphs = 0;
1824
1825     unsigned currentCharacter = iterator->currentCharacter;
1826     const UniChar *cp = &run->characters[currentCharacter];
1827
1828     const WebCoreTextStyle *style = iterator->style;
1829     bool rtl = style->rtl;
1830     bool needCharTransform = rtl || style->smallCaps;
1831     bool hasExtraSpacing = style->letterSpacing || style->wordSpacing || style->padding;
1832
1833     float runWidthSoFar = iterator->runWidthSoFar;
1834     float lastRoundingWidth = iterator->finalRoundingWidth;
1835
1836     while (currentCharacter < offset) {
1837         UChar32 c = *cp;
1838
1839         unsigned clusterLength = 1;
1840         if (c >= 0x3041) {
1841             if (c <= 0x30FE) {
1842                 // Deal with Hiragana and Katakana voiced and semi-voiced syllables.
1843                 // Normalize into composed form, and then look for glyph with base + combined mark.
1844                 // Check above for character range to minimize performance impact.
1845                 UChar32 normalized = normalizeVoicingMarks(iterator);
1846                 if (normalized) {
1847                     c = normalized;
1848                     clusterLength = 2;
1849                 }
1850             } else if (U16_IS_SURROGATE(c)) {
1851                 if (!U16_IS_SURROGATE_LEAD(c))
1852                     break;
1853
1854                 // Do we have a surrogate pair?  If so, determine the full Unicode (32 bit)
1855                 // code point before glyph lookup.
1856                 // Make sure we have another character and it's a low surrogate.
1857                 if (currentCharacter + 1 >= run->length)
1858                     break;
1859                 UniChar low = cp[1];
1860                 if (!U16_IS_TRAIL(low))
1861                     break;
1862                 c = U16_GET_SUPPLEMENTARY(c, low);
1863                 clusterLength = 2;
1864             }
1865         }
1866
1867         const FontData *renderer = iterator->renderer;
1868
1869         if (needCharTransform) {
1870             if (rtl)
1871                 c = u_charMirror(c);
1872
1873             // If small-caps, convert lowercase to upper.
1874             if (style->smallCaps && !u_isUUppercase(c)) {
1875                 UChar32 upperC = u_toupper(c);
1876                 if (upperC != c) {
1877                     c = upperC;
1878                     renderer = renderer->smallCapsFontData();
1879                 }
1880             }
1881         }
1882
1883         Glyph glyph = renderer->glyphForCharacter(&renderer, c);
1884
1885         // Now that we have glyph and font, get its width.
1886         WebGlyphWidth width;
1887         if (c == '\t' && style->tabWidth) {
1888             width = style->tabWidth - fmodf(style->xpos + runWidthSoFar, style->tabWidth);
1889         } else {
1890             width = renderer->widthForGlyph(glyph);
1891             // We special case spaces in two ways when applying word rounding.
1892             // First, we round spaces to an adjusted width in all fonts.
1893             // Second, in fixed-pitch fonts we ensure that all characters that
1894             // match the width of the space character have the same width as the space character.
1895             if (width == renderer->m_spaceWidth && (renderer->m_treatAsFixedPitch || glyph == renderer->m_spaceGlyph) && style->applyWordRounding)
1896                 width = renderer->m_adjustedSpaceWidth;
1897         }
1898
1899         // Try to find a substitute font if this font didn't have a glyph for a character in the
1900         // string. If one isn't found we end up drawing and measuring the 0 glyph, usually a box.
1901         if (glyph == 0 && style->attemptFontSubstitution) {
1902             FontData *substituteRenderer = (FontData*)findSubstituteRenderer(renderer, cp, clusterLength, style->families);
1903             if (substituteRenderer) {
1904                 WebCoreTextRun clusterRun = { cp, clusterLength, 0, clusterLength };
1905                 WebCoreTextStyle clusterStyle = *style;
1906                 clusterStyle.padding = 0;
1907                 clusterStyle.applyRunRounding = NO;
1908                 clusterStyle.attemptFontSubstitution = NO;
1909                 
1910                 int cNumGlyphs;
1911                 float localWidthBuffer[MAX_GLYPH_EXPANSION];
1912                 FontData *localRendererBuffer[MAX_GLYPH_EXPANSION];
1913                 ATSGlyphRef localGlyphBuffer[MAX_GLYPH_EXPANSION];            
1914                 CG_floatWidthForRun(substituteRenderer, &clusterRun, &clusterStyle, localWidthBuffer, localRendererBuffer, localGlyphBuffer, 0, &cNumGlyphs);
1915                 if (cNumGlyphs == 1) {
1916                     assert(substituteRenderer == localRendererBuffer[0]);
1917                     width = localWidthBuffer[0];
1918                     glyph = localGlyphBuffer[0];
1919                     renderer->updateGlyphMapEntry(c, glyph, substituteRenderer);
1920                     renderer = substituteRenderer;
1921                 }
1922             }
1923         }
1924
1925         if (hasExtraSpacing) {
1926             // Account for letter-spacing.
1927             if (width && style->letterSpacing)
1928                 width += style->letterSpacing;
1929
1930             if (isSpace(c)) {
1931                 // Account for padding. WebCore uses space padding to justify text.
1932                 // We distribute the specified padding over the available spaces in the run.
1933                 if (style->padding) {
1934                     // Use left over padding if not evenly divisible by number of spaces.
1935                     if (iterator->padding < iterator->padPerSpace) {
1936                         width += iterator->padding;
1937                         iterator->padding = 0;
1938                     } else {
1939                         width += iterator->padPerSpace;
1940                         iterator->padding -= iterator->padPerSpace;
1941                     }
1942                 }
1943
1944                 // Account for word spacing.
1945                 // We apply additional space between "words" by adding width to the space character.
1946                 if (currentCharacter != 0 && !isSpace(cp[-1]) && style->wordSpacing)
1947                     width += style->wordSpacing;
1948             }
1949         }
1950
1951         // Advance past the character we just dealt with.
1952         cp += clusterLength;
1953         currentCharacter += clusterLength;
1954
1955         // Account for float/integer impedance mismatch between CG and KHTML. "Words" (characters 
1956         // followed by a character defined by isRoundingHackCharacter()) are always an integer width.
1957         // We adjust the width of the last character of a "word" to ensure an integer width.
1958         // If we move KHTML to floats we can remove this (and related) hacks.
1959
1960         float oldWidth = width;
1961
1962         // Force characters that are used to determine word boundaries for the rounding hack
1963         // to be integer width, so following words will start on an integer boundary.
1964         if (style->applyWordRounding && isRoundingHackCharacter(c))
1965             width = ceilf(width);
1966
1967         // Check to see if the next character is a "rounding hack character", if so, adjust
1968         // width so that the total run width will be on an integer boundary.
1969         if ((style->applyWordRounding && currentCharacter < run->length && isRoundingHackCharacter(*cp))
1970                 || (style->applyRunRounding && currentCharacter >= (unsigned)run->to)) {
1971             float totalWidth = iterator->widthToStart + runWidthSoFar + width;
1972             width += ceilf(totalWidth) - totalWidth;
1973         }
1974
1975         runWidthSoFar += width;
1976
1977         if (!widths) {
1978             assert(!renderersUsed);
1979             assert(!glyphsUsed);
1980         } else {
1981             assert(renderersUsed);
1982             assert(glyphsUsed);
1983             *widths++ = (rtl ? oldWidth + lastRoundingWidth : width);
1984             *renderersUsed++ = (FontData*)renderer;
1985             *glyphsUsed++ = glyph;
1986         }
1987
1988         lastRoundingWidth = width - oldWidth;
1989         ++numGlyphs;
1990     }
1991
1992     iterator->currentCharacter = currentCharacter;
1993     iterator->runWidthSoFar = runWidthSoFar;
1994     iterator->finalRoundingWidth = lastRoundingWidth;
1995
1996     return numGlyphs;
1997 }
1998
1999 static bool fillStyleWithAttributes(ATSUStyle style, NSFont *theFont)
2000 {
2001     if (!theFont)
2002         return NO;
2003     ATSUFontID fontId = wkGetNSFontATSUFontId(theFont);
2004     if (!fontId)
2005         return NO;
2006     ATSUAttributeTag tag = kATSUFontTag;
2007     ByteCount size = sizeof(ATSUFontID);
2008     ATSUFontID *valueArray[1] = {&fontId};
2009     OSStatus status = ATSUSetAttributes(style, 1, &tag, &size, (void* const*)valueArray);
2010     if (status != noErr)
2011         return NO;
2012     return YES;
2013 }
2014
2015 static bool shouldUseATSU(const WebCoreTextRun *run)
2016 {
2017     if (Font::gAlwaysUseComplexPath)
2018         return YES;
2019         
2020     const UniChar *characters = run->characters;
2021     int to = run->to;
2022     int i;
2023     // Start from 0 since drawing and highlighting also measure the characters before run->from
2024     for (i = 0; i < to; i++) {
2025         UniChar c = characters[i];
2026         if (c < 0x300)      // U+0300 through U+036F Combining diacritical marks
2027             continue;
2028         if (c <= 0x36F)
2029             return YES;
2030
2031         if (c < 0x0591 || c == 0x05BE)     // U+0591 through U+05CF excluding U+05BE Hebrew combining marks, Hebrew punctuation Paseq, Sof Pasuq and Nun Hafukha
2032             continue;
2033         if (c <= 0x05CF)
2034             return YES;
2035
2036         if (c < 0x0600)     // U+0600 through U+1059 Arabic, Syriac, Thaana, Devanagari, Bengali, Gurmukhi, Gujarati, Oriya, Tamil, Telugu, Kannada, Malayalam, Sinhala, Thai, Lao, Tibetan, Myanmar
2037             continue;
2038         if (c <= 0x1059)
2039             return YES;
2040
2041         if (c < 0x1100)     // U+1100 through U+11FF Hangul Jamo (only Ancient Korean should be left here if you precompose; Modern Korean will be precomposed as a result of step A)
2042             continue;
2043         if (c <= 0x11FF)
2044             return YES;
2045
2046         if (c < 0x1780)     // U+1780 through U+18AF Khmer, Mongolian
2047             continue;
2048         if (c <= 0x18AF)
2049             return YES;
2050
2051         if (c < 0x1900)     // U+1900 through U+194F Limbu (Unicode 4.0)
2052             continue;
2053         if (c <= 0x194F)
2054             return YES;
2055
2056         if (c < 0x20D0)     // U+20D0 through U+20FF Combining marks for symbols
2057             continue;
2058         if (c <= 0x20FF)
2059             return YES;
2060
2061         if (c < 0xFE20)     // U+FE20 through U+FE2F Combining half marks
2062             continue;
2063         if (c <= 0xFE2F)
2064             return YES;
2065     }
2066
2067     return NO;
2068 }
2069
2070 }