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