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