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