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