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