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