Remove the misspelling drawing code from Font and FontData. Implement it
[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 int FontData::pointToOffset(const WebCoreTextRun* run, const WebCoreTextStyle* style, int x, bool includePartialGlyphs)
524 {
525     if (shouldUseATSU(run))
526         return ATSU_pointToOffset(this, run, style, x, includePartialGlyphs);
527     return CG_pointToOffset(this, run, style, x, includePartialGlyphs);
528 }
529
530 FontData* FontData::smallCapsFontData() const
531 {
532     if (!m_smallCapsFontData) {
533         NS_DURING
534             float size = [m_font.font pointSize] * SMALLCAPS_FONTSIZE_MULTIPLIER;
535             FontPlatformData smallCapsFont;
536             WebCoreInitializeFont(&smallCapsFont);
537             smallCapsFont.font = [[NSFontManager sharedFontManager] convertFont:m_font.font toSize:size];
538             m_smallCapsFontData = (FontData*)rendererForAlternateFont(this, smallCapsFont);
539         NS_HANDLER
540             NSLog(@"uncaught exception selecting font for small caps: %@", localException);
541         NS_ENDHANDLER
542     }
543     return m_smallCapsFontData;
544 }
545
546 static inline bool fontContainsString(NSFont *font, NSString *string)
547 {
548     NSCharacterSet *set = [[font coveredCharacterSet] invertedSet];
549     return set && [string rangeOfCharacterFromSet:set].location == NSNotFound;
550 }
551
552 static NSFont *findSubstituteFont(const FontData *renderer, NSString *string, NSString **families)
553 {
554     NSFont *substituteFont = nil;
555
556     // First search the CSS family fallback list.
557     // Start at 1 (2nd font) because we've already failed on the first lookup.
558     NSString *family = nil;
559     int i = 1;
560     while (families && families[i]) {
561         family = families[i++];
562         NSFont *f = [[WebTextRendererFactory sharedFactory] cachedFontFromFamily:family
563             traits:[[NSFontManager sharedFontManager] traitsOfFont:renderer->m_font.font]
564             size:[renderer->m_font.font pointSize]];
565         if (f && fontContainsString(f, string)) {
566             substituteFont = f; 
567             break;
568         }
569     }
570     
571     // Now do string based lookup.
572     if (substituteFont == nil)
573         substituteFont = wkGetFontInLanguageForRange(renderer->m_font.font, string, NSMakeRange(0, [string length]));
574
575     // Now do character based lookup.
576     if (substituteFont == nil && [string length] == 1)
577         substituteFont = wkGetFontInLanguageForCharacter(renderer->m_font.font, [string characterAtIndex:0]);
578
579     // Check to make sure this is a distinct font.
580     if (substituteFont && [[substituteFont screenFont] isEqual:[renderer->m_font.font screenFont]])
581         substituteFont = nil;
582
583     // Now that we have a substitute font, attempt to match it to the best variation.
584     // If we have a good match return that, otherwise return the font the AppKit has found.
585     if (substituteFont) {
586         NSFontManager *manager = [NSFontManager sharedFontManager];
587         NSFont *bestVariation = [manager fontWithFamily:[substituteFont familyName]
588             traits:[manager traitsOfFont:renderer->m_font.font]
589             weight:[manager weightOfFont:renderer->m_font.font]
590             size:[renderer->m_font.font pointSize]];
591         if (bestVariation)
592             substituteFont = bestVariation;
593     }
594
595     return substituteFont;
596 }
597
598 static const FontData *rendererForAlternateFont(const FontData *renderer, FontPlatformData alternateFont)
599 {
600     if (!alternateFont.font)
601         return nil;
602
603     NSFontManager *fontManager = [NSFontManager sharedFontManager];
604     NSFontTraitMask fontTraits = [fontManager traitsOfFont:renderer->m_font.font];
605     if (renderer->m_font.syntheticBold)
606         fontTraits |= NSBoldFontMask;
607     if (renderer->m_font.syntheticOblique)
608         fontTraits |= NSItalicFontMask;
609     NSFontTraitMask alternateFontTraits = [fontManager traitsOfFont:alternateFont.font];
610
611     alternateFont.syntheticBold = (fontTraits & NSBoldFontMask) && !(alternateFontTraits & NSBoldFontMask);
612     alternateFont.syntheticOblique = (fontTraits & NSItalicFontMask) && !(alternateFontTraits & NSItalicFontMask);
613     alternateFont.forPrinter = renderer->m_font.forPrinter;
614
615     return [[WebTextRendererFactory sharedFactory] rendererWithFont:alternateFont];
616 }
617
618 static const FontData *findSubstituteRenderer(const FontData *renderer, const unichar *characters, int numCharacters, NSString **families)
619 {
620     FontPlatformData substituteFont;
621     WebCoreInitializeFont(&substituteFont);
622     NSString *string = [[NSString alloc] initWithCharactersNoCopy:(unichar *)characters length: numCharacters freeWhenDone: NO];
623     substituteFont.font = findSubstituteFont(renderer, string, families);
624     [string release];
625     return rendererForAlternateFont(renderer, substituteFont);
626 }
627
628 const FontData* FontData::findSubstituteFontData(const UChar* characters, unsigned numCharacters, const FontDescription& fontDescription) const
629 {
630     CREATE_FAMILY_ARRAY(fontDescription, families);
631     return findSubstituteRenderer(this, (const unichar*)characters, numCharacters, families);
632 }
633
634 // Nasty hack to determine if we should round or ceil space widths.
635 // If the font is monospace or fake monospace we ceil to ensure that 
636 // every character and the space are the same width.  Otherwise we round.
637 static bool computeWidthForSpace(FontData *renderer)
638 {
639     renderer->m_spaceGlyph = extendGlyphMap(renderer, SPACE);
640     if (renderer->m_spaceGlyph == 0)
641         return NO;
642
643     float width = renderer->widthForGlyph(renderer->m_spaceGlyph);
644
645     renderer->m_spaceWidth = width;
646
647     renderer->m_treatAsFixedPitch = [[WebTextRendererFactory sharedFactory] isFontFixedPitch:renderer->m_font];
648     renderer->m_adjustedSpaceWidth = renderer->m_treatAsFixedPitch ? ceilf(width) : roundf(width);
649     
650     return YES;
651 }
652
653 static bool setUpFont(FontData *renderer)
654 {
655     renderer->m_font.font = renderer->m_font.forPrinter ? [renderer->m_font.font printerFont] : [renderer->m_font.font screenFont];
656
657     ATSUStyle fontStyle;
658     if (ATSUCreateStyle(&fontStyle) != noErr)
659         return NO;
660
661     if (!fillStyleWithAttributes(fontStyle, renderer->m_font.font)) {
662         ATSUDisposeStyle(fontStyle);
663         return NO;
664     }
665
666     if (wkGetATSStyleGroup(fontStyle, &renderer->m_styleGroup) != noErr) {
667         ATSUDisposeStyle(fontStyle);
668         return NO;
669     }
670
671     ATSUDisposeStyle(fontStyle);
672
673     if (!computeWidthForSpace(renderer)) {
674         freeGlyphMap(renderer->m_characterToGlyphMap);
675         renderer->m_characterToGlyphMap = 0;
676         wkReleaseStyleGroup(renderer->m_styleGroup);
677         renderer->m_styleGroup = 0;
678         return NO;
679     }
680     
681     return YES;
682 }
683
684 #if !ERROR_DISABLED
685
686 static NSString *pathFromFont(NSFont *font)
687 {
688     FSSpec oFile;
689     OSStatus status = ATSFontGetFileSpecification(FMGetATSFontRefFromFont((FMFont)wkGetNSFontATSUFontId(font)), &oFile);
690     if (status == noErr) {
691         OSErr err;
692         FSRef fileRef;
693         err = FSpMakeFSRef(&oFile, &fileRef);
694         if (err == noErr) {
695             UInt8 filePathBuffer[PATH_MAX];
696             status = FSRefMakePath(&fileRef, filePathBuffer, PATH_MAX);
697             if (status == noErr)
698                 return [NSString stringWithUTF8String:(const char *)filePathBuffer];
699         }
700     }
701     return nil;
702 }
703
704 #endif
705
706 // Useful page for testing http://home.att.net/~jameskass
707 static void drawGlyphs(NSFont *font, NSColor *color, CGGlyph *glyphs, CGSize *advances, float x, float y, int numGlyphs,
708     float syntheticBoldOffset, bool syntheticOblique)
709 {
710     NSGraphicsContext *gContext = [NSGraphicsContext currentContext];
711     CGContextRef cgContext = (CGContextRef)[gContext graphicsPort];
712
713     bool originalShouldUseFontSmoothing = wkCGContextGetShouldSmoothFonts(cgContext);
714     CGContextSetShouldSmoothFonts(cgContext, WebCoreShouldUseFontSmoothing());
715     
716     NSFont *drawFont;
717     if ([gContext isDrawingToScreen]) {
718         drawFont = [font screenFont];
719         if (drawFont != font)
720             // 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).
721             LOG_ERROR("Attempting to set non-screen font (%@) when drawing to screen.  Using screen font anyway, may result in incorrect metrics.",
722                 [[[font fontDescriptor] fontAttributes] objectForKey:NSFontNameAttribute]);
723     } else {
724         drawFont = [font printerFont];
725         if (drawFont != font)
726             NSLog(@"Attempting to set non-printer font (%@) when printing.  Using printer font anyway, may result in incorrect metrics.",
727                 [[[font fontDescriptor] fontAttributes] objectForKey:NSFontNameAttribute]);
728     }
729     
730     CGContextSetFont(cgContext, wkGetCGFontFromNSFont(drawFont));
731
732     CGAffineTransform matrix;
733     memcpy(&matrix, [drawFont matrix], sizeof(matrix));
734     if ([gContext isFlipped]) {
735         matrix.b = -matrix.b;
736         matrix.d = -matrix.d;
737     }
738     if (syntheticOblique)
739         matrix = CGAffineTransformConcat(matrix, CGAffineTransformMake(1, 0, -tanf(SYNTHETIC_OBLIQUE_ANGLE * acosf(0) / 90), 1, 0, 0)); 
740     CGContextSetTextMatrix(cgContext, matrix);
741
742     wkSetCGFontRenderingMode(cgContext, drawFont);
743     CGContextSetFontSize(cgContext, 1.0f);
744
745     [color set];
746
747     CGContextSetTextPosition(cgContext, x, y);
748     CGContextShowGlyphsWithAdvances(cgContext, glyphs, advances, numGlyphs);
749     if (syntheticBoldOffset) {
750         CGContextSetTextPosition(cgContext, x + syntheticBoldOffset, y);
751         CGContextShowGlyphsWithAdvances(cgContext, glyphs, advances, numGlyphs);
752     }
753
754     CGContextSetShouldSmoothFonts(cgContext, originalShouldUseFontSmoothing);
755 }
756
757 static NSRect CG_selectionRect(FontData *renderer, const WebCoreTextRun * run, const WebCoreTextStyle *style, const WebCoreTextGeometry *geometry)
758 {
759     float yPos = geometry->useFontMetricsForSelectionYAndHeight
760         ? geometry->point.y() - renderer->ascent() - (renderer->lineGap() / 2) : geometry->selectionY;
761     float height = geometry->useFontMetricsForSelectionYAndHeight
762         ? renderer->lineSpacing() : geometry->selectionHeight;
763
764     WebCoreTextRun completeRun = *run;
765     completeRun.from = 0;
766     completeRun.to = run->length;
767
768     WidthIterator it;
769     initializeWidthIterator(&it, renderer, &completeRun, style);
770     
771     advanceWidthIterator(&it, run->from, 0, 0, 0);
772     float beforeWidth = it.runWidthSoFar;
773     advanceWidthIterator(&it, run->to, 0, 0, 0);
774     float afterWidth = it.runWidthSoFar;
775     // Using roundf() rather than ceilf() for the right edge as a compromise to ensure correct caret positioning
776     if (style->rtl) {
777         advanceWidthIterator(&it, run->length, 0, 0, 0);
778         float totalWidth = it.runWidthSoFar;
779         return NSMakeRect(geometry->point.x() + floorf(totalWidth - afterWidth), yPos, roundf(totalWidth - beforeWidth) - floorf(totalWidth - afterWidth), height);
780     } else {
781         return NSMakeRect(geometry->point.x() + floorf(beforeWidth), yPos, roundf(afterWidth) - floorf(beforeWidth), height);
782     }
783 }
784
785 static void CG_draw(FontData *renderer, const WebCoreTextRun *run, const WebCoreTextStyle *style, const WebCoreTextGeometry *geometry)
786 {
787     float *widthBuffer, localWidthBuffer[LOCAL_BUFFER_SIZE];
788     CGGlyph *glyphBuffer, localGlyphBuffer[LOCAL_BUFFER_SIZE];
789     FontData **rendererBuffer, *localRendererBuffer[LOCAL_BUFFER_SIZE];
790     CGSize *advances, localAdvanceBuffer[LOCAL_BUFFER_SIZE];
791     int numGlyphs = 0, i;
792     float startX;
793     unsigned length = run->length;
794     
795     if (run->length == 0)
796         return;
797
798     if (length * MAX_GLYPH_EXPANSION > LOCAL_BUFFER_SIZE) {
799         advances = new CGSize[length * MAX_GLYPH_EXPANSION];
800         widthBuffer = new float[length * MAX_GLYPH_EXPANSION];
801         glyphBuffer = new CGGlyph[length * MAX_GLYPH_EXPANSION];
802         rendererBuffer = new FontData*[length * MAX_GLYPH_EXPANSION];
803     } else {
804         advances = localAdvanceBuffer;
805         widthBuffer = localWidthBuffer;
806         glyphBuffer = localGlyphBuffer;
807         rendererBuffer = localRendererBuffer;
808     }
809
810     CG_floatWidthForRun(renderer, run, style, widthBuffer, rendererBuffer, glyphBuffer, &startX, &numGlyphs);
811         
812     // Eek.  We couldn't generate ANY glyphs for the run.
813     if (numGlyphs <= 0)
814         return;
815         
816     // Fill the advances array.
817     for (i = 0; i < numGlyphs; i++) {
818         advances[i].width = widthBuffer[i];
819         advances[i].height = 0;
820     }
821
822     // Calculate the starting point of the glyphs to be displayed by adding
823     // all the advances up to the first glyph.
824     startX += geometry->point.x();
825     
826     // Swap the order of the glyphs if right-to-left.
827     if (style->rtl) {
828         int i;
829         int mid = numGlyphs / 2;
830         int end;
831         for (i = 0, end = numGlyphs - 1; i < mid; ++i, --end) {
832             CGGlyph gswap1 = glyphBuffer[i];
833             CGGlyph gswap2 = glyphBuffer[end];
834             glyphBuffer[i] = gswap2;
835             glyphBuffer[end] = gswap1;
836
837             CGSize aswap1 = advances[i];
838             CGSize aswap2 = advances[end];
839             advances[i] = aswap2;
840             advances[end] = aswap1;
841
842             FontData *rswap1 = rendererBuffer[i];
843             FontData *rswap2 = rendererBuffer[end];
844             rendererBuffer[i] = rswap2;
845             rendererBuffer[end] = rswap1;
846         }
847     }
848
849     // Draw each contiguous run of glyphs that use the same renderer.
850     FontData *currentRenderer = rendererBuffer[0];
851     float nextX = startX;
852     int lastFrom = 0;
853     int nextGlyph = 0;
854     while (nextGlyph < numGlyphs) {
855         FontData *nextRenderer = rendererBuffer[nextGlyph];
856         if (nextRenderer != currentRenderer) {
857             drawGlyphs(currentRenderer->m_font.font, style->textColor, &glyphBuffer[lastFrom], &advances[lastFrom],
858                 startX, geometry->point.y(), nextGlyph - lastFrom,
859                 currentRenderer->m_syntheticBoldOffset, currentRenderer->m_font.syntheticOblique);
860             lastFrom = nextGlyph;
861             currentRenderer = nextRenderer;
862             startX = nextX;
863         }
864         nextX += advances[nextGlyph].width;
865         nextGlyph++;
866     }
867     drawGlyphs(currentRenderer->m_font.font, style->textColor, &glyphBuffer[lastFrom], &advances[lastFrom],
868         startX, geometry->point.y(), nextGlyph - lastFrom,
869         currentRenderer->m_syntheticBoldOffset, currentRenderer->m_font.syntheticOblique);
870
871     if (advances != localAdvanceBuffer) {
872         delete []advances;
873         delete []widthBuffer;
874         delete []glyphBuffer;
875         delete []rendererBuffer;
876     }
877 }
878
879 static float CG_floatWidthForRun(FontData *renderer, const WebCoreTextRun *run, const WebCoreTextStyle *style, float *widthBuffer, FontData **rendererBuffer, CGGlyph *glyphBuffer, float *startPosition, int *numGlyphsResult)
880 {
881     WidthIterator it;
882     WebCoreTextRun completeRun;
883     const WebCoreTextRun *aRun;
884     if (!style->rtl)
885         aRun = run;
886     else {
887         completeRun = *run;
888         completeRun.to = run->length;
889         aRun = &completeRun;
890     }
891     initializeWidthIterator(&it, renderer, aRun, style);
892     int numGlyphs = advanceWidthIterator(&it, run->to, widthBuffer, rendererBuffer, glyphBuffer);
893     float runWidth = it.runWidthSoFar;
894     if (startPosition) {
895         if (!style->rtl)
896             *startPosition = it.widthToStart;
897         else {
898             float finalRoundingWidth = it.finalRoundingWidth;
899             advanceWidthIterator(&it, run->length, 0, 0, 0);
900             *startPosition = it.runWidthSoFar - runWidth + finalRoundingWidth;
901         }
902     }
903     if (numGlyphsResult)
904         *numGlyphsResult = numGlyphs;
905     return runWidth;
906 }
907
908 void FontData::updateGlyphMapEntry(UChar c, ATSGlyphRef glyph, const FontData *substituteRenderer) const
909 {
910     GlyphMap *map;
911     for (map = m_characterToGlyphMap; map; map = map->next) {
912         UChar32 start = map->startRange;
913         if (c >= start && c <= map->endRange) {
914             int i = c - start;
915             map->glyphs[i].glyph = glyph;
916             // This renderer will leak.
917             // No problem though; we want it to stick around forever.
918             // Max theoretical retain counts applied here will be num_fonts_on_system * num_glyphs_in_font.
919             map->glyphs[i].renderer = substituteRenderer;
920             break;
921         }
922     }
923 }
924
925 static ATSGlyphRef extendGlyphMap(const FontData *renderer, UChar32 c)
926 {
927     GlyphMap *map = new GlyphMap;
928     ATSLayoutRecord *glyphRecord;
929     char glyphVector[WKGlyphVectorSize];
930     UChar32 end, start;
931     unsigned blockSize;
932     
933     if (renderer->m_characterToGlyphMap == 0)
934         blockSize = INITIAL_BLOCK_SIZE;
935     else
936         blockSize = INCREMENTAL_BLOCK_SIZE;
937     start = (c / blockSize) * blockSize;
938     end = start + (blockSize - 1);
939
940     map->startRange = start;
941     map->endRange = end;
942     map->next = 0;
943     
944     unsigned i;
945     unsigned count = end - start + 1;
946     unsigned short buffer[INCREMENTAL_BLOCK_SIZE * 2 + 2];
947     unsigned bufferLength;
948
949     if (start < 0x10000) {
950         bufferLength = count;
951         for (i = 0; i < count; i++)
952             buffer[i] = i + start;
953
954         if (start == 0) {
955             // Control characters must not render at all.
956             for (i = 0; i < 0x20; ++i)
957                 buffer[i] = ZERO_WIDTH_SPACE;
958             buffer[0x7F] = ZERO_WIDTH_SPACE;
959
960             // But \n, \t, and nonbreaking space must render as a space.
961             buffer[(int)'\n'] = ' ';
962             buffer[(int)'\t'] = ' ';
963             buffer[NO_BREAK_SPACE] = ' ';
964         }
965     } else {
966         bufferLength = count * 2;
967         for (i = 0; i < count; i++) {
968             int c = i + start;
969             buffer[i * 2] = U16_LEAD(c);
970             buffer[i * 2 + 1] = U16_TRAIL(c);
971         }
972     }
973
974     OSStatus status = wkInitializeGlyphVector(count, &glyphVector);
975     if (status != noErr) {
976         // This should never happen, perhaps indicates a bad font!  If it does the
977         // font substitution code will find an alternate font.
978         delete map;
979         return 0;
980     }
981
982     wkConvertCharToGlyphs(renderer->m_styleGroup, &buffer[0], bufferLength, &glyphVector);
983     unsigned numGlyphs = wkGetGlyphVectorNumGlyphs(&glyphVector);
984     if (numGlyphs != count) {
985         // This should never happen, perhaps indicates a bad font?
986         // If it does happen, the font substitution code will find an alternate font.
987         wkClearGlyphVector(&glyphVector);
988         delete map;
989         return 0;
990     }
991
992     map->glyphs = new GlyphEntry[count];
993     glyphRecord = (ATSLayoutRecord *)wkGetGlyphVectorFirstRecord(glyphVector);
994     for (i = 0; i < count; i++) {
995         map->glyphs[i].glyph = glyphRecord->glyphID;
996         map->glyphs[i].renderer = renderer;
997         glyphRecord = (ATSLayoutRecord *)((char *)glyphRecord + wkGetGlyphVectorRecordSize(glyphVector));
998     }
999     wkClearGlyphVector(&glyphVector);
1000     
1001     if (renderer->m_characterToGlyphMap == 0)
1002         renderer->m_characterToGlyphMap = map;
1003     else {
1004         GlyphMap *lastMap = renderer->m_characterToGlyphMap;
1005         while (lastMap->next != 0)
1006             lastMap = lastMap->next;
1007         lastMap->next = map;
1008     }
1009
1010     ATSGlyphRef glyph = map->glyphs[c - start].glyph;
1011
1012     // Special case for characters 007F-00A0.
1013     if (glyph == 0 && c >= 0x7F && c <= 0xA0) {
1014         glyph = wkGetDefaultGlyphForChar(renderer->m_font.font, c);
1015         map->glyphs[c - start].glyph = glyph;
1016     }
1017
1018     return glyph;
1019 }
1020
1021 static WidthMap *extendWidthMap(const FontData *renderer, ATSGlyphRef glyph)
1022 {
1023     WidthMap *map = new WidthMap;
1024     unsigned end;
1025     ATSGlyphRef start;
1026     unsigned blockSize;
1027     unsigned i, count;
1028     
1029     NSFont *f = renderer->m_font.font;
1030     if (renderer->m_glyphToWidthMap == 0) {
1031         if ([f numberOfGlyphs] < INITIAL_BLOCK_SIZE)
1032             blockSize = [f numberOfGlyphs];
1033          else
1034             blockSize = INITIAL_BLOCK_SIZE;
1035     } else {
1036         blockSize = INCREMENTAL_BLOCK_SIZE;
1037     }
1038     if (blockSize == 0) {
1039         start = 0;
1040     } else {
1041         start = (glyph / blockSize) * blockSize;
1042     }
1043     end = ((unsigned)start) + blockSize; 
1044
1045     map->startRange = start;
1046     map->endRange = end;
1047     count = end - start + 1;
1048
1049     map->widths = new WebGlyphWidth[count];
1050     for (i = 0; i < count; i++)
1051         map->widths[i] = NAN;
1052
1053     if (renderer->m_glyphToWidthMap == 0)
1054         renderer->m_glyphToWidthMap = map;
1055     else {
1056         WidthMap *lastMap = renderer->m_glyphToWidthMap;
1057         while (lastMap->next != 0)
1058             lastMap = lastMap->next;
1059         lastMap->next = map;
1060     }
1061
1062     return map;
1063 }
1064
1065 static void initializeATSUStyle(FontData *renderer)
1066 {
1067     // The two NSFont calls in this method (pointSize and _atsFontID) do not raise exceptions.
1068
1069     if (!renderer->m_ATSUStyleInitialized) {
1070         OSStatus status;
1071         ByteCount propTableSize;
1072         
1073         status = ATSUCreateStyle(&renderer->m_ATSUStyle);
1074         if (status != noErr)
1075             LOG_ERROR("ATSUCreateStyle failed (%d)", status);
1076     
1077         ATSUFontID fontID = wkGetNSFontATSUFontId(renderer->m_font.font);
1078         if (fontID == 0) {
1079             ATSUDisposeStyle(renderer->m_ATSUStyle);
1080             LOG_ERROR("unable to get ATSUFontID for %@", renderer->m_font.font);
1081             return;
1082         }
1083         
1084         CGAffineTransform transform = CGAffineTransformMakeScale(1, -1);
1085         if (renderer->m_font.syntheticOblique)
1086             transform = CGAffineTransformConcat(transform, CGAffineTransformMake(1, 0, -tanf(SYNTHETIC_OBLIQUE_ANGLE * acosf(0) / 90), 1, 0, 0)); 
1087         Fixed fontSize = FloatToFixed([renderer->m_font.font pointSize]);
1088         // Turn off automatic kerning until it is supported in the CG code path (6136 in bugzilla)
1089         Fract kerningInhibitFactor = FloatToFract(1.0);
1090         ATSUAttributeTag styleTags[4] = { kATSUSizeTag, kATSUFontTag, kATSUFontMatrixTag, kATSUKerningInhibitFactorTag };
1091         ByteCount styleSizes[4] = { sizeof(Fixed), sizeof(ATSUFontID), sizeof(CGAffineTransform), sizeof(Fract) };
1092         ATSUAttributeValuePtr styleValues[4] = { &fontSize, &fontID, &transform, &kerningInhibitFactor };
1093         status = ATSUSetAttributes(renderer->m_ATSUStyle, 4, styleTags, styleSizes, styleValues);
1094         if (status != noErr)
1095             LOG_ERROR("ATSUSetAttributes failed (%d)", status);
1096         status = ATSFontGetTable(fontID, 'prop', 0, 0, 0, &propTableSize);
1097         if (status == noErr)    // naively assume that if a 'prop' table exists then it contains mirroring info
1098             renderer->m_ATSUMirrors = true;
1099         else if (status == kATSInvalidFontTableAccess)
1100             renderer->m_ATSUMirrors = false;
1101         else
1102             LOG_ERROR("ATSFontGetTable failed (%d)", status);
1103
1104         // Turn off ligatures such as 'fi' to match the CG code path's behavior, until bugzilla 6135 is fixed.
1105         // Don't be too aggressive: if the font doesn't contain 'a', then assume that any ligatures it contains are
1106         // in characters that always go through ATSUI, and therefore allow them. Geeza Pro is an example.
1107         // See bugzilla 5166.
1108         if ([[renderer->m_font.font coveredCharacterSet] characterIsMember:'a']) {
1109             ATSUFontFeatureType featureTypes[] = { kLigaturesType };
1110             ATSUFontFeatureSelector featureSelectors[] = { kCommonLigaturesOffSelector };
1111             status = ATSUSetFontFeatures(renderer->m_ATSUStyle, 1, featureTypes, featureSelectors);
1112         }
1113
1114         renderer->m_ATSUStyleInitialized = true;
1115     }
1116 }
1117
1118 static void createATSULayoutParameters(ATSULayoutParameters *params, FontData *renderer, const WebCoreTextRun *run, const WebCoreTextStyle *style)
1119 {
1120     params->run = run;
1121     params->style = style;
1122     // FIXME: It is probably best to always allocate a buffer for RTL, since even if for this
1123     // renderer ATSUMirrors is true, for a substitute renderer it might be false.
1124     FontData** renderers = new FontData*[run->length];
1125     params->renderers = renderers;
1126     UniChar *charBuffer = (UniChar*)((style->smallCaps || (style->rtl && !renderer->m_ATSUMirrors)) ? new UniChar[run->length] : 0);
1127     params->charBuffer = charBuffer;
1128     params->syntheticBoldPass = false;
1129
1130     // The only Cocoa calls here are to NSGraphicsContext, which does not raise exceptions.
1131
1132     ATSUTextLayout layout;
1133     OSStatus status;
1134     ATSULayoutOperationOverrideSpecifier overrideSpecifier;
1135     
1136     initializeATSUStyle(renderer);
1137     
1138     // FIXME: This is currently missing the following required features that the CoreGraphics code path has:
1139     // - \n, \t, and nonbreaking space render as a space.
1140     // - Other control characters do not render (other code path uses zero-width spaces).
1141
1142     UniCharCount totalLength = run->length;
1143     UniCharArrayOffset runTo = (run->to == -1 ? totalLength : (unsigned int)run->to);
1144     UniCharArrayOffset runFrom = run->from;
1145     
1146     if (charBuffer)
1147         memcpy(charBuffer, run->characters, totalLength * sizeof(UniChar));
1148
1149     UniCharCount runLength = runTo - runFrom;
1150     
1151     status = ATSUCreateTextLayoutWithTextPtr(
1152             (charBuffer ? charBuffer : run->characters),
1153             runFrom,        // offset
1154             runLength,      // length
1155             totalLength,    // total length
1156             1,              // styleRunCount
1157             &runLength,     // length of style run
1158             &renderer->m_ATSUStyle, 
1159             &layout);
1160     if (status != noErr)
1161         LOG_ERROR("ATSUCreateTextLayoutWithTextPtr failed(%d)", status);
1162     params->layout = layout;
1163     ATSUSetTextLayoutRefCon(layout, (UInt32)params);
1164
1165     CGContextRef cgContext = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
1166     ATSLineLayoutOptions lineLayoutOptions = kATSLineKeepSpacesOutOfMargin | kATSLineHasNoHangers;
1167     Boolean rtl = style->rtl;
1168     overrideSpecifier.operationSelector = kATSULayoutOperationPostLayoutAdjustment;
1169     overrideSpecifier.overrideUPP = overrideLayoutOperation;
1170     ATSUAttributeTag tags[] = { kATSUCGContextTag, kATSULineLayoutOptionsTag, kATSULineDirectionTag, kATSULayoutOperationOverrideTag };
1171     ByteCount sizes[] = { sizeof(CGContextRef), sizeof(ATSLineLayoutOptions), sizeof(Boolean), sizeof(ATSULayoutOperationOverrideSpecifier) };
1172     ATSUAttributeValuePtr values[] = { &cgContext, &lineLayoutOptions, &rtl, &overrideSpecifier };
1173     
1174     status = ATSUSetLayoutControls(layout, (style->applyWordRounding ? 4 : 3), tags, sizes, values);
1175     if (status != noErr)
1176         LOG_ERROR("ATSUSetLayoutControls failed(%d)", status);
1177
1178     status = ATSUSetTransientFontMatching(layout, YES);
1179     if (status != noErr)
1180         LOG_ERROR("ATSUSetTransientFontMatching failed(%d)", status);
1181
1182     params->hasSyntheticBold = false;
1183     ATSUFontID ATSUSubstituteFont;
1184     UniCharArrayOffset substituteOffset = runFrom;
1185     UniCharCount substituteLength;
1186     UniCharArrayOffset lastOffset;
1187     FontData *substituteRenderer = 0;
1188
1189     while (substituteOffset < runTo) {
1190         lastOffset = substituteOffset;
1191         status = ATSUMatchFontsToText(layout, substituteOffset, kATSUToTextEnd, &ATSUSubstituteFont, &substituteOffset, &substituteLength);
1192         if (status == kATSUFontsMatched || status == kATSUFontsNotMatched) {
1193             substituteRenderer = (FontData*)findSubstituteRenderer(renderer, run->characters+substituteOffset, substituteLength, style->families);
1194             if (substituteRenderer) {
1195                 initializeATSUStyle(substituteRenderer);
1196                 if (substituteRenderer->m_ATSUStyle)
1197                     ATSUSetRunStyle(layout, substituteRenderer->m_ATSUStyle, substituteOffset, substituteLength);
1198             } else
1199                 substituteRenderer = renderer;
1200         } else {
1201             substituteOffset = runTo;
1202             substituteLength = 0;
1203         }
1204
1205         bool isSmallCap = false;
1206         UniCharArrayOffset firstSmallCap = 0;
1207         FontData *r = renderer;
1208         UniCharArrayOffset i;
1209         for (i = lastOffset;  ; i++) {
1210             if (i == substituteOffset || i == substituteOffset + substituteLength) {
1211                 if (isSmallCap) {
1212                     isSmallCap = false;
1213                     initializeATSUStyle(r->smallCapsFontData());
1214                     ATSUSetRunStyle(layout, r->smallCapsFontData()->m_ATSUStyle, firstSmallCap, i - firstSmallCap);
1215                 }
1216                 if (i == substituteOffset && substituteLength > 0)
1217                     r = substituteRenderer;
1218                 else
1219                     break;
1220             }
1221             if (rtl && charBuffer && !r->m_ATSUMirrors)
1222                 charBuffer[i] = u_charMirror(charBuffer[i]);
1223             if (style->smallCaps) {
1224                 UniChar c = charBuffer[i];
1225                 UniChar newC;
1226                 if (U_GET_GC_MASK(c) & U_GC_M_MASK)
1227                     renderers[i] = isSmallCap ? r->smallCapsFontData() : r;
1228                 else if (!u_isUUppercase(c) && (newC = u_toupper(c)) != c) {
1229                     charBuffer[i] = newC;
1230                     if (!isSmallCap) {
1231                         isSmallCap = true;
1232                         firstSmallCap = i;
1233                     }
1234                     renderers[i] = r->smallCapsFontData();
1235                 } else {
1236                     if (isSmallCap) {
1237                         isSmallCap = false;
1238                         initializeATSUStyle(r->smallCapsFontData());
1239                         ATSUSetRunStyle(layout, r->smallCapsFontData()->m_ATSUStyle, firstSmallCap, i - firstSmallCap);
1240                     }
1241                     renderers[i] = r;
1242                 }
1243             } else
1244                 renderers[i] = r;
1245             if (renderers[i]->m_syntheticBoldOffset)
1246                 params->hasSyntheticBold = true;
1247         }
1248         substituteOffset += substituteLength;
1249     }
1250     if (style->padding) {
1251         float numSpaces = 0;
1252         unsigned k;
1253         for (k = 0; k < totalLength; k++)
1254             if (Font::treatAsSpace(run->characters[k]))
1255                 numSpaces++;
1256
1257         params->padPerSpace = ceilf(style->padding / numSpaces);
1258     } else
1259         params->padPerSpace = 0;
1260 }
1261
1262 static void disposeATSULayoutParameters(ATSULayoutParameters *params)
1263 {
1264     ATSUDisposeTextLayout(params->layout);
1265     delete []params->charBuffer;
1266     delete []params->renderers;
1267 }
1268
1269 static ATSTrapezoid getTextBounds(FontData *renderer, const WebCoreTextRun *run, const WebCoreTextStyle *style, NSPoint p)
1270 {
1271     OSStatus status;
1272     
1273     if (run->to - run->from <= 0) {
1274         ATSTrapezoid nilTrapezoid = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
1275         return nilTrapezoid;
1276     }
1277
1278     ATSULayoutParameters params;
1279     createATSULayoutParameters(&params, renderer, run, style);
1280
1281     ATSTrapezoid firstGlyphBounds;
1282     ItemCount actualNumBounds;
1283     status = ATSUGetGlyphBounds(params.layout, FloatToFixed(p.x), FloatToFixed(p.y), run->from, run->to - run->from, kATSUseFractionalOrigins, 1, &firstGlyphBounds, &actualNumBounds);    
1284     if (status != noErr)
1285         LOG_ERROR("ATSUGetGlyphBounds() failed(%d)", status);
1286     if (actualNumBounds != 1)
1287         LOG_ERROR("unexpected result from ATSUGetGlyphBounds(): actualNumBounds(%d) != 1", actualNumBounds);
1288
1289     disposeATSULayoutParameters(&params);
1290
1291     return firstGlyphBounds;
1292 }
1293
1294 static float ATSU_floatWidthForRun(FontData *renderer, const WebCoreTextRun *run, const WebCoreTextStyle *style)
1295 {
1296     ATSTrapezoid oGlyphBounds = getTextBounds(renderer, run, style, NSZeroPoint);
1297     return MAX(FixedToFloat(oGlyphBounds.upperRight.x), FixedToFloat(oGlyphBounds.lowerRight.x)) -
1298         MIN(FixedToFloat(oGlyphBounds.upperLeft.x), FixedToFloat(oGlyphBounds.lowerLeft.x));
1299 }
1300
1301 // Be sure to free the run.characters allocated by this function.
1302 static WebCoreTextRun addDirectionalOverride(const WebCoreTextRun *run, bool rtl)
1303 {
1304     int from = run->from;
1305     int to = run->to;
1306     if (from == -1)
1307         from = 0;
1308     if (to == -1)
1309         to = run->length;
1310
1311     UniChar *charactersWithOverride = new UniChar[run->length + 2];
1312
1313     charactersWithOverride[0] = rtl ? RIGHT_TO_LEFT_OVERRIDE : LEFT_TO_RIGHT_OVERRIDE;
1314     memcpy(&charactersWithOverride[1], &run->characters[0], sizeof(UniChar) * run->length);
1315     charactersWithOverride[run->length + 1] = POP_DIRECTIONAL_FORMATTING;
1316
1317     WebCoreTextRun runWithOverride;
1318
1319     runWithOverride.from = from + 1;
1320     runWithOverride.to = to + 1;
1321     runWithOverride.length = run->length + 2;
1322     runWithOverride.characters = charactersWithOverride;
1323
1324     return runWithOverride;
1325 }
1326
1327 static NSRect ATSU_selectionRect(FontData *renderer, const WebCoreTextRun *run, const WebCoreTextStyle *style, const WebCoreTextGeometry *geometry)
1328 {
1329     int from = run->from;
1330     int to = run->to;
1331     if (from == -1)
1332         from = 0;
1333     if (to == -1)
1334         to = run->length;
1335         
1336     WebCoreTextRun completeRun = *run;
1337     completeRun.from = 0;
1338     completeRun.to = run->length;
1339     
1340     WebCoreTextRun *aRun = &completeRun;
1341     WebCoreTextRun swappedRun;
1342     
1343     if (style->directionalOverride) {
1344         swappedRun = addDirectionalOverride(aRun, style->rtl);
1345         aRun = &swappedRun;
1346         from++;
1347         to++;
1348     }
1349    
1350     ATSULayoutParameters params;
1351     createATSULayoutParameters(&params, renderer, aRun, style);
1352     
1353     ATSTrapezoid firstGlyphBounds;
1354     ItemCount actualNumBounds;
1355     
1356     OSStatus status = ATSUGetGlyphBounds(params.layout, 0, 0, from, to - from, kATSUseFractionalOrigins, 1, &firstGlyphBounds, &actualNumBounds);
1357     if (status != noErr || actualNumBounds != 1) {
1358         static ATSTrapezoid zeroTrapezoid = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
1359         firstGlyphBounds = zeroTrapezoid;
1360     }
1361     disposeATSULayoutParameters(&params);    
1362     
1363     float beforeWidth = MIN(FixedToFloat(firstGlyphBounds.lowerLeft.x), FixedToFloat(firstGlyphBounds.upperLeft.x));
1364     float afterWidth = MAX(FixedToFloat(firstGlyphBounds.lowerRight.x), FixedToFloat(firstGlyphBounds.upperRight.x));
1365     float yPos = geometry->useFontMetricsForSelectionYAndHeight
1366         ? geometry->point.y() - renderer->ascent() : geometry->selectionY;
1367     float height = geometry->useFontMetricsForSelectionYAndHeight
1368         ? renderer->lineSpacing() : geometry->selectionHeight;
1369
1370     NSRect rect = NSMakeRect(geometry->point.x() + floorf(beforeWidth), yPos, roundf(afterWidth) - floorf(beforeWidth), height);
1371
1372     if (style->directionalOverride)
1373         delete []swappedRun.characters;
1374
1375     return rect;
1376 }
1377
1378
1379 static void ATSU_draw(FontData *renderer, const WebCoreTextRun *run, const WebCoreTextStyle *style, const WebCoreTextGeometry *geometry)
1380 {
1381     // The only Cocoa calls made here are to NSColor and NSGraphicsContext, and they do not raise exceptions.
1382
1383     OSStatus status;
1384     int from, to;
1385     const WebCoreTextRun *aRun = run;
1386     WebCoreTextRun swappedRun;
1387     
1388     if (style->directionalOverride) {
1389         swappedRun = addDirectionalOverride(run, style->rtl);
1390         aRun = &swappedRun;
1391     }
1392
1393     from = aRun->from;
1394     to = aRun->to;
1395     if (from == -1)
1396         from = 0;
1397     if (to == -1)
1398         to = run->length;
1399
1400     int runLength = to - from;
1401     if (runLength <= 0)
1402         return;
1403
1404     WebCoreTextRun completeRun = *aRun;
1405     completeRun.from = 0;
1406     completeRun.to = aRun->length;
1407     ATSULayoutParameters params;
1408     createATSULayoutParameters(&params, renderer, &completeRun, style);
1409
1410     [style->textColor set];
1411
1412     // ATSUI can't draw beyond -32768 to +32767 so we translate the CTM and tell ATSUI to draw at (0, 0).
1413     NSGraphicsContext *gContext = [NSGraphicsContext currentContext];
1414     CGContextRef context = (CGContextRef)[gContext graphicsPort];
1415     CGContextTranslateCTM(context, geometry->point.x(), geometry->point.y());
1416     bool flipped = [gContext isFlipped];
1417     if (!flipped)
1418         CGContextScaleCTM(context, 1.0, -1.0);
1419     status = ATSUDrawText(params.layout, aRun->from, runLength, 0, 0);
1420     if (status == noErr && params.hasSyntheticBold) {
1421         // Force relayout for the bold pass
1422         ATSUClearLayoutCache(params.layout, 0);
1423         params.syntheticBoldPass = true;
1424         status = ATSUDrawText(params.layout, aRun->from, runLength, 0, 0);
1425     }
1426     if (!flipped)
1427         CGContextScaleCTM(context, 1.0, -1.0);
1428     CGContextTranslateCTM(context, -geometry->point.x(), -geometry->point.y());
1429
1430     if (status != noErr) {
1431         // Nothing to do but report the error (dev build only).
1432         LOG_ERROR("ATSUDrawText() failed(%d)", status);
1433     }
1434
1435     disposeATSULayoutParameters(&params);
1436     
1437     if (style->directionalOverride)
1438         delete []swappedRun.characters;
1439 }
1440
1441 static int ATSU_pointToOffset(FontData *renderer, const WebCoreTextRun *run, const WebCoreTextStyle *style,
1442     int x, bool includePartialGlyphs)
1443 {
1444     const WebCoreTextRun *aRun = run;
1445     WebCoreTextRun swappedRun;
1446     
1447     // Enclose in LRO/RLO - PDF to force ATSU to render visually.
1448     if (style->directionalOverride) {
1449         swappedRun = addDirectionalOverride(aRun, style->rtl);
1450         aRun = &swappedRun;
1451     }
1452
1453     ATSULayoutParameters params;
1454     createATSULayoutParameters(&params, renderer, aRun, style);
1455
1456     UniCharArrayOffset primaryOffset = aRun->from;
1457     
1458     // FIXME: No idea how to avoid including partial glyphs.
1459     // Not even sure if that's the behavior this yields now.
1460     Boolean isLeading;
1461     UniCharArrayOffset secondaryOffset = 0;
1462     OSStatus status = ATSUPositionToOffset(params.layout, FloatToFixed(x), FloatToFixed(-1), &primaryOffset, &isLeading, &secondaryOffset);
1463     unsigned offset;
1464     if (status == noErr) {
1465         offset = (unsigned)primaryOffset;
1466     } else {
1467         // Failed to find offset!  Return 0 offset.
1468         offset = 0;
1469     }
1470
1471     disposeATSULayoutParameters(&params);
1472     
1473     if (style->directionalOverride)
1474         delete []swappedRun.characters;
1475
1476     return offset - aRun->from;
1477 }
1478
1479 static bool advanceWidthIteratorOneCharacter(WidthIterator *iterator, float *totalWidth)
1480 {
1481     float widths[MAX_GLYPH_EXPANSION];
1482     FontData *renderers[MAX_GLYPH_EXPANSION];
1483     ATSGlyphRef glyphs[MAX_GLYPH_EXPANSION];            
1484     unsigned numGlyphs = advanceWidthIterator(iterator, iterator->currentCharacter + 1, widths, renderers, glyphs);
1485     unsigned i;
1486     float w = 0;
1487     for (i = 0; i < numGlyphs; ++i)
1488         w += widths[i];
1489     *totalWidth = w;
1490     return numGlyphs != 0;
1491 }
1492
1493 static int CG_pointToOffset(FontData *renderer, const WebCoreTextRun * run, const WebCoreTextStyle *style,
1494     int x, bool includePartialGlyphs)
1495 {
1496     float delta = (float)x;
1497
1498     WidthIterator it;    
1499     initializeWidthIterator(&it, renderer, run, style);
1500
1501     unsigned offset;
1502
1503     if (style->rtl) {
1504         delta -= CG_floatWidthForRun(renderer, run, style, 0, 0, 0, 0, 0);
1505         while (1) {
1506             offset = it.currentCharacter;
1507             float w;
1508             if (!advanceWidthIteratorOneCharacter(&it, &w))
1509                 break;
1510             delta += w;
1511             if (includePartialGlyphs) {
1512                 if (delta - w / 2 >= 0)
1513                     break;
1514             } else {
1515                 if (delta >= 0)
1516                     break;
1517             }
1518         }
1519     } else {
1520         while (1) {
1521             offset = it.currentCharacter;
1522             float w;
1523             if (!advanceWidthIteratorOneCharacter(&it, &w))
1524                 break;
1525             delta -= w;
1526             if (includePartialGlyphs) {
1527                 if (delta + w / 2 <= 0)
1528                     break;
1529             } else {
1530                 if (delta <= 0)
1531                     break;
1532             }
1533         }
1534     }
1535
1536     return offset - run->from;
1537 }
1538
1539 static void freeWidthMap(WidthMap *map)
1540 {
1541     while (map) {
1542         WidthMap *next = map->next;
1543         delete []map->widths;
1544         delete map;
1545         map = next;
1546     }
1547 }
1548
1549 static void freeGlyphMap(GlyphMap *map)
1550 {
1551     while (map) {
1552         GlyphMap *next = map->next;
1553         delete []map->glyphs;
1554         delete map;
1555         map = next;
1556     }
1557 }
1558
1559 Glyph FontData::glyphForCharacter(const FontData **renderer, unsigned c) const
1560 {
1561     // this loop is hot, so it is written to avoid LSU stalls
1562     GlyphMap *map;
1563     GlyphMap *nextMap;
1564     for (map = (*renderer)->m_characterToGlyphMap; map; map = nextMap) {
1565         UChar start = map->startRange;
1566         nextMap = map->next;
1567         if (c >= start && c <= map->endRange) {
1568             GlyphEntry *ge = &map->glyphs[c - start];
1569             *renderer = ge->renderer;
1570             return ge->glyph;
1571         }
1572     }
1573
1574     return extendGlyphMap(*renderer, c);
1575 }
1576
1577 static void initializeWidthIterator(WidthIterator *iterator, FontData *renderer, const WebCoreTextRun *run, const WebCoreTextStyle *style) 
1578 {
1579     iterator->renderer = renderer;
1580     iterator->run = run;
1581     iterator->style = style;
1582     iterator->currentCharacter = run->from;
1583     iterator->runWidthSoFar = 0;
1584     iterator->finalRoundingWidth = 0;
1585
1586     // If the padding is non-zero, count the number of spaces in the run
1587     // and divide that by the padding for per space addition.
1588     if (!style->padding) {
1589         iterator->padding = 0;
1590         iterator->padPerSpace = 0;
1591     } else {
1592         float numSpaces = 0;
1593         int k;
1594         for (k = run->from; k < run->to; k++)
1595             if (Font::treatAsSpace(run->characters[k]))
1596                 numSpaces++;
1597
1598         iterator->padding = style->padding;
1599         iterator->padPerSpace = ceilf(iterator->padding / numSpaces);
1600     }
1601     
1602     // Calculate width up to starting position of the run.  This is
1603     // necessary to ensure that our rounding hacks are always consistently
1604     // applied.
1605     if (run->from == 0) {
1606         iterator->widthToStart = 0;
1607     } else {
1608         WebCoreTextRun startPositionRun = *run;
1609         startPositionRun.from = 0;
1610         startPositionRun.to = run->length;
1611         WidthIterator startPositionIterator;
1612         initializeWidthIterator(&startPositionIterator, renderer, &startPositionRun, style);
1613         advanceWidthIterator(&startPositionIterator, run->from, 0, 0, 0);
1614         iterator->widthToStart = startPositionIterator.runWidthSoFar;
1615     }
1616 }
1617
1618 static UChar32 normalizeVoicingMarks(WidthIterator *iterator)
1619 {
1620     unsigned currentCharacter = iterator->currentCharacter;
1621     const WebCoreTextRun *run = iterator->run;
1622     if (currentCharacter + 1 < (unsigned)run->to) {
1623         if (u_getCombiningClass(run->characters[currentCharacter + 1]) == HIRAGANA_KATAKANA_VOICING_MARKS) {
1624             // Normalize into composed form using 3.2 rules.
1625             UChar normalizedCharacters[2] = { 0, 0 };
1626             UErrorCode uStatus = (UErrorCode)0;                
1627             int32_t resultLength = unorm_normalize(&run->characters[currentCharacter], 2,
1628                 UNORM_NFC, UNORM_UNICODE_3_2, &normalizedCharacters[0], 2, &uStatus);
1629             if (resultLength == 1 && uStatus == 0)
1630                 return normalizedCharacters[0];
1631         }
1632     }
1633     return 0;
1634 }
1635
1636 static unsigned advanceWidthIterator(WidthIterator *iterator, unsigned offset, float *widths, FontData **renderersUsed, ATSGlyphRef *glyphsUsed)
1637 {
1638     const WebCoreTextRun *run = iterator->run;
1639     if (offset > (unsigned)run->to)
1640         offset = run->to;
1641
1642     unsigned numGlyphs = 0;
1643
1644     unsigned currentCharacter = iterator->currentCharacter;
1645     const UniChar *cp = &run->characters[currentCharacter];
1646
1647     const WebCoreTextStyle *style = iterator->style;
1648     bool rtl = style->rtl;
1649     bool needCharTransform = rtl || style->smallCaps;
1650     bool hasExtraSpacing = style->letterSpacing || style->wordSpacing || style->padding;
1651
1652     float runWidthSoFar = iterator->runWidthSoFar;
1653     float lastRoundingWidth = iterator->finalRoundingWidth;
1654
1655     while (currentCharacter < offset) {
1656         UChar32 c = *cp;
1657
1658         unsigned clusterLength = 1;
1659         if (c >= 0x3041) {
1660             if (c <= 0x30FE) {
1661                 // Deal with Hiragana and Katakana voiced and semi-voiced syllables.
1662                 // Normalize into composed form, and then look for glyph with base + combined mark.
1663                 // Check above for character range to minimize performance impact.
1664                 UChar32 normalized = normalizeVoicingMarks(iterator);
1665                 if (normalized) {
1666                     c = normalized;
1667                     clusterLength = 2;
1668                 }
1669             } else if (U16_IS_SURROGATE(c)) {
1670                 if (!U16_IS_SURROGATE_LEAD(c))
1671                     break;
1672
1673                 // Do we have a surrogate pair?  If so, determine the full Unicode (32 bit)
1674                 // code point before glyph lookup.
1675                 // Make sure we have another character and it's a low surrogate.
1676                 if (currentCharacter + 1 >= run->length)
1677                     break;
1678                 UniChar low = cp[1];
1679                 if (!U16_IS_TRAIL(low))
1680                     break;
1681                 c = U16_GET_SUPPLEMENTARY(c, low);
1682                 clusterLength = 2;
1683             }
1684         }
1685
1686         const FontData *renderer = iterator->renderer;
1687
1688         if (needCharTransform) {
1689             if (rtl)
1690                 c = u_charMirror(c);
1691
1692             // If small-caps, convert lowercase to upper.
1693             if (style->smallCaps && !u_isUUppercase(c)) {
1694                 UChar32 upperC = u_toupper(c);
1695                 if (upperC != c) {
1696                     c = upperC;
1697                     renderer = renderer->smallCapsFontData();
1698                 }
1699             }
1700         }
1701
1702         Glyph glyph = renderer->glyphForCharacter(&renderer, c);
1703
1704         // Now that we have glyph and font, get its width.
1705         WebGlyphWidth width;
1706         if (c == '\t' && style->tabWidth) {
1707             width = style->tabWidth - fmodf(style->xpos + runWidthSoFar, style->tabWidth);
1708         } else {
1709             width = renderer->widthForGlyph(glyph);
1710             // We special case spaces in two ways when applying word rounding.
1711             // First, we round spaces to an adjusted width in all fonts.
1712             // Second, in fixed-pitch fonts we ensure that all characters that
1713             // match the width of the space character have the same width as the space character.
1714             if (width == renderer->m_spaceWidth && (renderer->m_treatAsFixedPitch || glyph == renderer->m_spaceGlyph) && style->applyWordRounding)
1715                 width = renderer->m_adjustedSpaceWidth;
1716         }
1717
1718         // Try to find a substitute font if this font didn't have a glyph for a character in the
1719         // string. If one isn't found we end up drawing and measuring the 0 glyph, usually a box.
1720         if (glyph == 0 && style->attemptFontSubstitution) {
1721             FontData *substituteRenderer = (FontData*)findSubstituteRenderer(renderer, cp, clusterLength, style->families);
1722             if (substituteRenderer) {
1723                 WebCoreTextRun clusterRun = { cp, clusterLength, 0, clusterLength };
1724                 WebCoreTextStyle clusterStyle = *style;
1725                 clusterStyle.padding = 0;
1726                 clusterStyle.applyRunRounding = NO;
1727                 clusterStyle.attemptFontSubstitution = NO;
1728                 
1729                 int cNumGlyphs;
1730                 float localWidthBuffer[MAX_GLYPH_EXPANSION];
1731                 FontData *localRendererBuffer[MAX_GLYPH_EXPANSION];
1732                 ATSGlyphRef localGlyphBuffer[MAX_GLYPH_EXPANSION];            
1733                 CG_floatWidthForRun(substituteRenderer, &clusterRun, &clusterStyle, localWidthBuffer, localRendererBuffer, localGlyphBuffer, 0, &cNumGlyphs);
1734                 if (cNumGlyphs == 1) {
1735                     assert(substituteRenderer == localRendererBuffer[0]);
1736                     width = localWidthBuffer[0];
1737                     glyph = localGlyphBuffer[0];
1738                     renderer->updateGlyphMapEntry(c, glyph, substituteRenderer);
1739                     renderer = substituteRenderer;
1740                 }
1741             }
1742         }
1743
1744         if (hasExtraSpacing) {
1745             // Account for letter-spacing.
1746             if (width && style->letterSpacing)
1747                 width += style->letterSpacing;
1748
1749             if (Font::treatAsSpace(c)) {
1750                 // Account for padding. WebCore uses space padding to justify text.
1751                 // We distribute the specified padding over the available spaces in the run.
1752                 if (style->padding) {
1753                     // Use left over padding if not evenly divisible by number of spaces.
1754                     if (iterator->padding < iterator->padPerSpace) {
1755                         width += iterator->padding;
1756                         iterator->padding = 0;
1757                     } else {
1758                         width += iterator->padPerSpace;
1759                         iterator->padding -= iterator->padPerSpace;
1760                     }
1761                 }
1762
1763                 // Account for word spacing.
1764                 // We apply additional space between "words" by adding width to the space character.
1765                 if (currentCharacter != 0 && !Font::treatAsSpace(cp[-1]) && style->wordSpacing)
1766                     width += style->wordSpacing;
1767             }
1768         }
1769
1770         // Advance past the character we just dealt with.
1771         cp += clusterLength;
1772         currentCharacter += clusterLength;
1773
1774         // Account for float/integer impedance mismatch between CG and KHTML. "Words" (characters 
1775         // followed by a character defined by isRoundingHackCharacter()) are always an integer width.
1776         // We adjust the width of the last character of a "word" to ensure an integer width.
1777         // If we move KHTML to floats we can remove this (and related) hacks.
1778
1779         float oldWidth = width;
1780
1781         // Force characters that are used to determine word boundaries for the rounding hack
1782         // to be integer width, so following words will start on an integer boundary.
1783         if (style->applyWordRounding && Font::isRoundingHackCharacter(c))
1784             width = ceilf(width);
1785
1786         // Check to see if the next character is a "rounding hack character", if so, adjust
1787         // width so that the total run width will be on an integer boundary.
1788         if ((style->applyWordRounding && currentCharacter < run->length && Font::isRoundingHackCharacter(*cp))
1789                 || (style->applyRunRounding && currentCharacter >= (unsigned)run->to)) {
1790             float totalWidth = iterator->widthToStart + runWidthSoFar + width;
1791             width += ceilf(totalWidth) - totalWidth;
1792         }
1793
1794         runWidthSoFar += width;
1795
1796         if (!widths) {
1797             assert(!renderersUsed);
1798             assert(!glyphsUsed);
1799         } else {
1800             assert(renderersUsed);
1801             assert(glyphsUsed);
1802             *widths++ = (rtl ? oldWidth + lastRoundingWidth : width);
1803             *renderersUsed++ = (FontData*)renderer;
1804             *glyphsUsed++ = glyph;
1805         }
1806
1807         lastRoundingWidth = width - oldWidth;
1808         ++numGlyphs;
1809     }
1810
1811     iterator->currentCharacter = currentCharacter;
1812     iterator->runWidthSoFar = runWidthSoFar;
1813     iterator->finalRoundingWidth = lastRoundingWidth;
1814
1815     return numGlyphs;
1816 }
1817
1818 static bool fillStyleWithAttributes(ATSUStyle style, NSFont *theFont)
1819 {
1820     if (!theFont)
1821         return NO;
1822     ATSUFontID fontId = wkGetNSFontATSUFontId(theFont);
1823     if (!fontId)
1824         return NO;
1825     ATSUAttributeTag tag = kATSUFontTag;
1826     ByteCount size = sizeof(ATSUFontID);
1827     ATSUFontID *valueArray[1] = {&fontId};
1828     OSStatus status = ATSUSetAttributes(style, 1, &tag, &size, (void* const*)valueArray);
1829     if (status != noErr)
1830         return NO;
1831     return YES;
1832 }
1833
1834 static bool shouldUseATSU(const WebCoreTextRun *run)
1835 {
1836     if (Font::gAlwaysUseComplexPath)
1837         return YES;
1838         
1839     const UniChar *characters = run->characters;
1840     int to = run->to;
1841     int i;
1842     // Start from 0 since drawing and highlighting also measure the characters before run->from
1843     for (i = 0; i < to; i++) {
1844         UniChar c = characters[i];
1845         if (c < 0x300)      // U+0300 through U+036F Combining diacritical marks
1846             continue;
1847         if (c <= 0x36F)
1848             return YES;
1849
1850         if (c < 0x0591 || c == 0x05BE)     // U+0591 through U+05CF excluding U+05BE Hebrew combining marks, Hebrew punctuation Paseq, Sof Pasuq and Nun Hafukha
1851             continue;
1852         if (c <= 0x05CF)
1853             return YES;
1854
1855         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
1856             continue;
1857         if (c <= 0x1059)
1858             return YES;
1859
1860         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)
1861             continue;
1862         if (c <= 0x11FF)
1863             return YES;
1864
1865         if (c < 0x1780)     // U+1780 through U+18AF Khmer, Mongolian
1866             continue;
1867         if (c <= 0x18AF)
1868             return YES;
1869
1870         if (c < 0x1900)     // U+1900 through U+194F Limbu (Unicode 4.0)
1871             continue;
1872         if (c <= 0x194F)
1873             return YES;
1874
1875         if (c < 0x20D0)     // U+20D0 through U+20FF Combining marks for symbols
1876             continue;
1877         if (c <= 0x20FF)
1878             return YES;
1879
1880         if (c < 0xFE20)     // U+FE20 through U+FE2F Combining half marks
1881             continue;
1882         if (c <= 0xFE2F)
1883             return YES;
1884     }
1885
1886     return NO;
1887 }
1888
1889 }