HTMLConverter.mm 123 KB
Newer Older
1
/*
2
 * Copyright (C) 2011, 2012 Apple Inc. All rights reserved.
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
 * THE POSSIBILITY OF SUCH DAMAGE.
 */

#import "config.h"
#import "HTMLConverter.h"

#import "ArchiveResource.h"
30
#import "CachedImage.h"
ap@apple.com's avatar
ap@apple.com committed
31
#import "ColorMac.h"
32
33
34
35
36
37
#import "Document.h"
#import "DocumentLoader.h"
#import "DOMDocumentInternal.h"
#import "DOMElementInternal.h"
#import "DOMHTMLTableCellElement.h"
#import "DOMPrivate.h"
ap@apple.com's avatar
ap@apple.com committed
38
#import "DOMRangeInternal.h"
39
#import "Element.h"
40
#import "Font.h"
41
#import "Frame.h"
42
#import "FrameLoader.h"
43
44
#import "HTMLNames.h"
#import "HTMLParserIdioms.h"
ap@apple.com's avatar
ap@apple.com committed
45
46
#import "LoaderNSURLExtras.h"
#import "RenderImage.h"
47
#import "SoftLinking.h"
ap@apple.com's avatar
ap@apple.com committed
48
#import "TextIterator.h"
49
#import <objc/runtime.h>
50
51
#import <wtf/ASCIICType.h>

52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
#if PLATFORM(IOS)

SOFT_LINK_FRAMEWORK(UIKit)
SOFT_LINK_CLASS(UIKit, UIColor)

SOFT_LINK_PRIVATE_FRAMEWORK(UIFoundation)
SOFT_LINK_CLASS(UIFoundation, UIFont)
SOFT_LINK_CLASS(UIFoundation, NSColor)
SOFT_LINK_CLASS(UIFoundation, NSShadow)
SOFT_LINK_CLASS(UIFoundation, NSTextAttachment)
SOFT_LINK_CLASS(UIFoundation, NSMutableParagraphStyle)
SOFT_LINK_CLASS(UIFoundation, NSParagraphStyle)
SOFT_LINK_CLASS(UIFoundation, NSTextList)
SOFT_LINK_CLASS(UIFoundation, NSTextBlock)
SOFT_LINK_CLASS(UIFoundation, NSTextTableBlock)
SOFT_LINK_CLASS(UIFoundation, NSTextTable)
SOFT_LINK_CLASS(UIFoundation, NSTextTab)

SOFT_LINK_CONSTANT(UIFoundation, NSFontAttributeName, NSString *)
#define NSFontAttributeName getNSFontAttributeName()
SOFT_LINK_CONSTANT(UIFoundation, NSForegroundColorAttributeName, NSString *)
#define NSForegroundColorAttributeName getNSForegroundColorAttributeName()
SOFT_LINK_CONSTANT(UIFoundation, NSBackgroundColorAttributeName, NSString *)
#define NSBackgroundColorAttributeName getNSBackgroundColorAttributeName()
SOFT_LINK_CONSTANT(UIFoundation, NSStrokeColorAttributeName, NSString *)
#define NSStrokeColorAttributeName getNSStrokeColorAttributeName()
SOFT_LINK_CONSTANT(UIFoundation, NSStrokeWidthAttributeName, NSString *)
#define NSStrokeWidthAttributeName getNSStrokeWidthAttributeName()
SOFT_LINK_CONSTANT(UIFoundation, NSShadowAttributeName, NSString *)
#define NSShadowAttributeName getNSShadowAttributeName()
SOFT_LINK_CONSTANT(UIFoundation, NSKernAttributeName, NSString *)
#define NSKernAttributeName getNSKernAttributeName()
SOFT_LINK_CONSTANT(UIFoundation, NSLigatureAttributeName, NSString *)
#define NSLigatureAttributeName getNSLigatureAttributeName()
SOFT_LINK_CONSTANT(UIFoundation, NSUnderlineStyleAttributeName, NSString *)
#define NSUnderlineStyleAttributeName getNSUnderlineStyleAttributeName()
SOFT_LINK_CONSTANT(UIFoundation, NSSuperscriptAttributeName, NSString *)
#define NSSuperscriptAttributeName getNSSuperscriptAttributeName()
SOFT_LINK_CONSTANT(UIFoundation, NSStrikethroughStyleAttributeName, NSString *)
#define NSStrikethroughStyleAttributeName getNSStrikethroughStyleAttributeName()
SOFT_LINK_CONSTANT(UIFoundation, NSBaselineOffsetAttributeName, NSString *)
#define NSBaselineOffsetAttributeName getNSBaselineOffsetAttributeName()
SOFT_LINK_CONSTANT(UIFoundation, NSWritingDirectionAttributeName, NSString *)
#define NSWritingDirectionAttributeName getNSWritingDirectionAttributeName()
SOFT_LINK_CONSTANT(UIFoundation, NSParagraphStyleAttributeName, NSString *)
#define NSParagraphStyleAttributeName getNSParagraphStyleAttributeName()
SOFT_LINK_CONSTANT(UIFoundation, NSAttachmentAttributeName, NSString *)
#define NSAttachmentAttributeName getNSAttachmentAttributeName()
SOFT_LINK_CONSTANT(UIFoundation, NSLinkAttributeName, NSString *)
#define NSLinkAttributeName getNSLinkAttributeName()
SOFT_LINK_CONSTANT(UIFoundation, NSAuthorDocumentAttribute, NSString *)
#define NSAuthorDocumentAttribute getNSAuthorDocumentAttribute()
SOFT_LINK_CONSTANT(UIFoundation, NSEditorDocumentAttribute, NSString *)
#define NSEditorDocumentAttribute getNSEditorDocumentAttribute()
SOFT_LINK_CONSTANT(UIFoundation, NSGeneratorDocumentAttribute, NSString *)
#define NSGeneratorDocumentAttribute getNSGeneratorDocumentAttribute()
SOFT_LINK_CONSTANT(UIFoundation, NSCompanyDocumentAttribute, NSString *)
#define NSCompanyDocumentAttribute getNSCompanyDocumentAttribute()
SOFT_LINK_CONSTANT(UIFoundation, NSDisplayNameDocumentAttribute, NSString *)
#define NSDisplayNameDocumentAttribute getNSDisplayNameDocumentAttribute()
SOFT_LINK_CONSTANT(UIFoundation, NSCopyrightDocumentAttribute, NSString *)
#define NSCopyrightDocumentAttribute getNSCopyrightDocumentAttribute()
SOFT_LINK_CONSTANT(UIFoundation, NSSubjectDocumentAttribute, NSString *)
#define NSSubjectDocumentAttribute getNSSubjectDocumentAttribute()
SOFT_LINK_CONSTANT(UIFoundation, NSCommentDocumentAttribute, NSString *)
#define NSCommentDocumentAttribute getNSCommentDocumentAttribute()
SOFT_LINK_CONSTANT(UIFoundation, NSNoIndexDocumentAttribute, NSString *)
#define NSNoIndexDocumentAttribute getNSNoIndexDocumentAttribute()
SOFT_LINK_CONSTANT(UIFoundation, NSKeywordsDocumentAttribute, NSString *)
#define NSKeywordsDocumentAttribute getNSKeywordsDocumentAttribute()
SOFT_LINK_CONSTANT(UIFoundation, NSCreationTimeDocumentAttribute, NSString *)
#define NSCreationTimeDocumentAttribute getNSCreationTimeDocumentAttribute()
SOFT_LINK_CONSTANT(UIFoundation, NSModificationTimeDocumentAttribute, NSString *)
#define NSModificationTimeDocumentAttribute getNSModificationTimeDocumentAttribute()
SOFT_LINK_CONSTANT(UIFoundation, NSConvertedDocumentAttribute, NSString *)
#define NSConvertedDocumentAttribute getNSConvertedDocumentAttribute()
SOFT_LINK_CONSTANT(UIFoundation, NSCocoaVersionDocumentAttribute, NSString *)
#define NSCocoaVersionDocumentAttribute getNSCocoaVersionDocumentAttribute()

#define PlatformNSShadow            getNSShadowClass()
#define PlatformNSTextAttachment    getNSTextAttachmentClass()
#define PlatformNSParagraphStyle    getNSParagraphStyleClass()
#define PlatformNSTextList          getNSTextListClass()
#define PlatformNSTextTableBlock    getNSTextTableBlockClass()
#define PlatformNSTextTable         getNSTextTableClass()
#define PlatformNSTextTab           getNSTextTabClass()
#define PlatformColor               UIColor
#define PlatformColorClass          getUIColorClass()
#define PlatformFont                UIFont
#define PlatformFontClass           getUIFontClass()
#else

#define PlatformNSShadow            NSShadow
#define PlatformNSTextAttachment    NSTextAttachment
#define PlatformNSParagraphStyle    NSParagraphStyle
#define PlatformNSTextList          NSTextList
#define PlatformNSTextTableBlock    NSTextTableBlock
#define PlatformNSTextTable         NSTextTable
#define PlatformNSTextTab           NSTextTab
#define PlatformColor               NSColor
#define PlatformColorClass          NSColor
#define PlatformFont                NSFont
#define PlatformFontClass           NSFont

#define NSTextAlignmentLeft         NSLeftTextAlignment
#define NSTextAlignmentRight        NSRightTextAlignment
#define NSTextAlignmentCenter       NSCenterTextAlignment
#define NSTextAlignmentJustified    NSJustifiedTextAlignment
#endif

162
163
164
using namespace WebCore;
using namespace HTMLNames;

165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
#if PLATFORM(IOS)

typedef enum {
    UIFontTraitPlain       = 0x00000000,
    UIFontTraitItalic      = 0x00000001, // 1 << 0
    UIFontTraitBold        = 0x00000002, // 1 << 1
    UIFontTraitThin        = (1 << 2),
    UIFontTraitLight       = (1 << 3),
    UIFontTraitUltraLight  = (1 << 4)
} UIFontTrait;

typedef NS_ENUM(NSInteger, NSUnderlineStyle) {
    NSUnderlineStyleNone                                = 0x00,
    NSUnderlineStyleSingle                              = 0x01,
    NSUnderlineStyleThick NS_ENUM_AVAILABLE_IOS(7_0)    = 0x02,
    NSUnderlineStyleDouble NS_ENUM_AVAILABLE_IOS(7_0)   = 0x09,

    NSUnderlinePatternSolid NS_ENUM_AVAILABLE_IOS(7_0)      = 0x0000,
    NSUnderlinePatternDot NS_ENUM_AVAILABLE_IOS(7_0)        = 0x0100,
    NSUnderlinePatternDash NS_ENUM_AVAILABLE_IOS(7_0)       = 0x0200,
    NSUnderlinePatternDashDot NS_ENUM_AVAILABLE_IOS(7_0)    = 0x0300,
    NSUnderlinePatternDashDotDot NS_ENUM_AVAILABLE_IOS(7_0) = 0x0400,

    NSUnderlineByWord NS_ENUM_AVAILABLE_IOS(7_0) = 0x8000
};

enum {
    NSTextBlockAbsoluteValueType    = 0,    // Absolute value in points
    NSTextBlockPercentageValueType  = 1     // Percentage value (out of 100)
};
typedef NSUInteger NSTextBlockValueType;

enum {
    NSTextBlockWidth            = 0,
    NSTextBlockMinimumWidth     = 1,
    NSTextBlockMaximumWidth     = 2,
    NSTextBlockHeight           = 4,
    NSTextBlockMinimumHeight    = 5,
    NSTextBlockMaximumHeight    = 6
};
typedef NSUInteger NSTextBlockDimension;

enum {
    NSTextBlockPadding  = -1,
    NSTextBlockBorder   =  0,
    NSTextBlockMargin   =  1
};
typedef NSInteger NSTextBlockLayer;

enum {
    NSTextTableAutomaticLayoutAlgorithm = 0,
    NSTextTableFixedLayoutAlgorithm     = 1
};
typedef NSUInteger NSTextTableLayoutAlgorithm;

enum {
    NSTextBlockTopAlignment         = 0,
    NSTextBlockMiddleAlignment      = 1,
    NSTextBlockBottomAlignment      = 2,
    NSTextBlockBaselineAlignment    = 3
};
typedef NSUInteger NSTextBlockVerticalAlignment;

typedef NS_ENUM(NSInteger, NSTextAlignment) {
    NSTextAlignmentLeft      = 0,    // Visually left aligned
    NSTextAlignmentCenter    = 1,    // Visually centered
    NSTextAlignmentRight     = 2,    // Visually right aligned
    NSTextAlignmentJustified = 3,    // Fully-justified. The last line in a paragraph is natural-aligned.
    NSTextAlignmentNatural   = 4,    // Indicates the default alignment for script
} NS_ENUM_AVAILABLE_IOS(6_0);

typedef NS_ENUM(NSInteger, NSWritingDirection) {
    NSWritingDirectionNatural       = -1,    // Determines direction using the Unicode Bidi Algorithm rules P2 and P3
    NSWritingDirectionLeftToRight   =  0,    // Left to right writing direction
    NSWritingDirectionRightToLeft   =  1     // Right to left writing direction
} NS_ENUM_AVAILABLE_IOS(6_0);

typedef NS_ENUM(NSInteger, NSTextWritingDirection) {
    NSTextWritingDirectionEmbedding     = (0 << 1),
    NSTextWritingDirectionOverride      = (1 << 1)
} NS_ENUM_AVAILABLE_IOS(7_0);

enum {
    NSEnterCharacter                = 0x0003,
    NSBackspaceCharacter            = 0x0008,
    NSTabCharacter                  = 0x0009,
    NSNewlineCharacter              = 0x000a,
    NSFormFeedCharacter             = 0x000c,
    NSCarriageReturnCharacter       = 0x000d,
    NSBackTabCharacter              = 0x0019,
    NSDeleteCharacter               = 0x007f,
    NSLineSeparatorCharacter        = 0x2028,
    NSParagraphSeparatorCharacter   = 0x2029,
    NSAttachmentCharacter           = 0xFFFC // Replacement character is used for attachments
};

enum {
    NSLeftTabStopType = 0,
    NSRightTabStopType,
    NSCenterTabStopType,
    NSDecimalTabStopType
};
typedef NSUInteger NSTextTabType;

@interface UIColor : NSObject
+ (UIColor *)clearColor;
- (CGFloat)alphaComponent;
+ (UIColor *)_disambiguated_due_to_CIImage_colorWithCGColor:(CGColorRef)cgColor;
@end

@interface NSColor : UIColor
+ (id)colorWithCalibratedRed:(CGFloat)red green:(CGFloat)green blue:(CGFloat)blue alpha:(CGFloat)alpha;
+ (id)colorWithCalibratedWhite:(CGFloat)white alpha:(CGFloat)alpha;
@end

@interface UIFont
+ (UIFont *)fontWithName:(NSString *)fontName size:(CGFloat)fontSize;
+ (UIFont *)fontWithFamilyName:(NSString *)familyName traits:(UIFontTrait)traits size:(CGFloat)fontSize;
- (NSString *)familyName;
- (CGFloat)pointSize;
- (UIFont *)fontWithSize:(CGFloat)fontSize;
+ (NSArray *)familyNames;
+ (NSArray *)fontNamesForFamilyName:(NSString *)familyName;
+ (UIFont *)systemFontOfSize:(CGFloat)fontSize;
@end

@interface NSTextTab
- (id)initWithType:(NSTextTabType)type location:(CGFloat)loc;
- (id)initWithTextAlignment:(NSTextAlignment)alignment location:(CGFloat)loc options:(NSDictionary *)options;
- (CGFloat)location;
- (void)release;
@end

@interface NSParagraphStyle : NSObject
+ (NSParagraphStyle *)defaultParagraphStyle;
- (void)setAlignment:(NSTextAlignment)alignment;
- (void)setBaseWritingDirection:(NSWritingDirection)writingDirection;
- (void)setHeadIndent:(CGFloat)aFloat;
- (CGFloat)headIndent;
- (void)setHeaderLevel:(NSInteger)level;
- (void)setFirstLineHeadIndent:(CGFloat)aFloat;
- (void)setTailIndent:(CGFloat)aFloat;
- (void)setParagraphSpacing:(CGFloat)paragraphSpacing;
- (void)setTextLists:(NSArray *)array;
- (void)setTextBlocks:(NSArray *)array;
- (void)setMinimumLineHeight:(CGFloat)aFloat;
- (NSArray *)textLists;
- (void)removeTabStop:(NSTextTab *)anObject;
- (void)addTabStop:(NSTextTab *)anObject;
- (NSArray *)tabStops;
- (void)setHyphenationFactor:(float)aFactor;
@end

@interface NSShadow
- (void)setShadowOffset:(CGSize)size;
- (void)setShadowBlurRadius:(CGFloat)radius;
- (void)setShadowColor:(UIColor *)color;
@end

@interface NSTextBlock : NSObject
- (void)setValue:(CGFloat)val type:(NSTextBlockValueType)type forDimension:(NSTextBlockDimension)dimension;
- (void)setWidth:(CGFloat)val type:(NSTextBlockValueType)type forLayer:(NSTextBlockLayer)layer edge:(NSRectEdge)edge;
- (void)setBackgroundColor:(UIColor *)color;
- (UIColor *)backgroundColor;
- (void)setBorderColor:(UIColor *)color forEdge:(NSRectEdge)edge;
- (void)setBorderColor:(UIColor *)color;        // Convenience method sets all edges at once
- (void)setVerticalAlignment:(NSTextBlockVerticalAlignment)alignment;
@end

@interface NSTextList
- (id)initWithMarkerFormat:(NSString *)format options:(NSUInteger)mask;
- (void)setStartingItemNumber:(NSInteger)itemNum;
- (NSInteger)startingItemNumber;
- (NSString *)markerForItemNumber:(NSInteger)itemNum;
- (void)release;
@end

@interface NSMutableParagraphStyle : NSParagraphStyle
- (void)setDefaultTabInterval:(CGFloat)aFloat;
- (void)setTabStops:(NSArray *)array;
@end

@interface NSTextAttachment : NSObject
- (id)initWithFileWrapper:(NSFileWrapper *)fileWrapper;
#if PLATFORM(IOS)
- (void)setBounds:(CGRect)bounds;
#endif
- (void)release;
@end

@interface NSTextTable : NSTextBlock
- (void)setNumberOfColumns:(NSUInteger)numCols;
- (void)setCollapsesBorders:(BOOL)flag;
- (void)setHidesEmptyCells:(BOOL)flag;
- (void)setLayoutAlgorithm:(NSTextTableLayoutAlgorithm)algorithm;
- (NSUInteger)numberOfColumns;
- (void)release;
@end

@interface NSTextTableBlock : NSTextBlock
- (id)initWithTable:(NSTextTable *)table startingRow:(NSInteger)row rowSpan:(NSInteger)rowSpan startingColumn:(NSInteger)col columnSpan:(NSInteger)colSpan;     // Designated initializer
- (NSInteger)startingColumn;
- (NSInteger)startingRow;
- (NSUInteger)numberOfColumns;
- (NSInteger)columnSpan;
- (NSInteger)rowSpan;
@end

#else
ap@apple.com's avatar
ap@apple.com committed
374
375
376
static NSFileWrapper *fileWrapperForURL(DocumentLoader *, NSURL *);
static NSFileWrapper *fileWrapperForElement(Element*);

377
378
379
380
381
382
383
384
@interface NSTextAttachment (WebCoreNSTextAttachment)
- (void)setIgnoresOrientation:(BOOL)flag;
- (void)setBounds:(CGRect)bounds;
- (BOOL)ignoresOrientation;
@end

#endif

385
386
387
// Additional control Unicode characters
const unichar WebNextLineCharacter = 0x0085;

ap@apple.com's avatar
ap@apple.com committed
388
@interface NSTextList (WebCoreNSTextListDetails)
389
390
391
+ (NSDictionary *)_standardMarkerAttributesForAttributes:(NSDictionary *)attrs;
@end

ap@apple.com's avatar
ap@apple.com committed
392
@interface NSURL (WebCoreNSURLDetails)
ap@apple.com's avatar
ap@apple.com committed
393
// FIXME: What is the reason to use this Foundation method, and not +[NSURL URLWithString:relativeToURL:]?
394
395
396
+ (NSURL *)_web_URLWithString:(NSString *)string relativeToURL:(NSURL *)baseURL;
@end

397
398
399
400
@interface NSObject(WebMessageDocumentSimulation)
+ (void)document:(NSObject **)outDocument attachment:(NSTextAttachment **)outAttachment forURL:(NSURL *)url;
@end

ap@apple.com's avatar
ap@apple.com committed
401
@interface WebHTMLConverter(WebHTMLConverterInternal)
402
403

- (NSString *)_stringForNode:(DOMNode *)node property:(NSString *)key;
404
- (PlatformColor *)_colorForNode:(DOMNode *)node property:(NSString *)key;
405
406
407
408
409
410
- (BOOL)_getFloat:(CGFloat *)val forNode:(DOMNode *)node property:(NSString *)key;
- (void)_traverseNode:(DOMNode *)node depth:(NSInteger)depth embedded:(BOOL)embedded;
- (void)_traverseFooterNode:(DOMNode *)node depth:(NSInteger)depth;

@end

411
412
413
@implementation WebHTMLConverter

#if !PLATFORM(IOS)
414
415
416
417
418
419
// Returns the font to be used if the NSFontAttributeName doesn't exist
static NSFont *WebDefaultFont()
{
    static NSFont *defaultFont = nil;
    if (defaultFont)
        return defaultFont;
420
421

    NSFont *font = [NSFont fontWithName:@"Helvetica" size:12];
422
423
    if (!font)
        font = [NSFont systemFontOfSize:12];
424

425
426
427
    defaultFont = [font retain];
    return defaultFont;
}
428
#endif
429

430
static PlatformFont *_fontForNameAndSize(NSString *fontName, CGFloat size, NSMutableDictionary *cache)
431
{
432
433
434
435
    PlatformFont *font = [cache objectForKey:fontName];
#if PLATFORM(IOS)
    if (font)
        return [font fontWithSize:size];
436

437
438
439
    font = [PlatformFontClass fontWithName:fontName size:size];
#else
    NSFontManager *fontManager = [NSFontManager sharedFontManager];
440
441
442
443
444
    if (font) {
        font = [fontManager convertFont:font toSize:size];
        return font;
    }
    font = [fontManager fontWithFamily:fontName traits:0 weight:0 size:size];
445
#endif
446
    if (!font) {
447
448
449
#if PLATFORM(IOS)
        NSArray *availableFamilyNames = [PlatformFontClass familyNames];
#else
450
        NSArray *availableFamilyNames = [fontManager availableFontFamilies];
451
452
453
454
#endif
        NSRange dividingRange;
        NSRange dividingSpaceRange = [fontName rangeOfString:@" " options:NSBackwardsSearch];
        NSRange dividingDashRange = [fontName rangeOfString:@"-" options:NSBackwardsSearch];
455
        dividingRange = (0 < dividingSpaceRange.length && 0 < dividingDashRange.length) ? (dividingSpaceRange.location > dividingDashRange.location ? dividingSpaceRange : dividingDashRange) : (0 < dividingSpaceRange.length ? dividingSpaceRange : dividingDashRange);
456
457

        while (dividingRange.length > 0) {
458
459
            NSString *familyName = [fontName substringToIndex:dividingRange.location];
            if ([availableFamilyNames containsObject:familyName]) {
460
461
462
463
464
465
466
467
468
469
470
471
#if PLATFORM(IOS)
                NSString *faceName = [fontName substringFromIndex:(dividingRange.location + dividingRange.length)];
                NSArray *familyMemberFaceNames = [PlatformFontClass fontNamesForFamilyName:familyName];
                for (NSString *familyMemberFaceName in familyMemberFaceNames) {
                    if ([familyMemberFaceName compare:faceName options:NSCaseInsensitiveSearch] == NSOrderedSame) {
                        font = [PlatformFontClass fontWithName:familyMemberFaceName size:size];
                        break;
                    }
                }
                if (!font && [familyMemberFaceNames count])
                    font = [getUIFontClass() fontWithName:familyName size:size];
#else
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
                NSArray *familyMemberArray;
                NSString *faceName = [fontName substringFromIndex:(dividingRange.location + dividingRange.length)];
                NSArray *familyMemberArrays = [fontManager availableMembersOfFontFamily:familyName];
                NSEnumerator *familyMemberArraysEnum = [familyMemberArrays objectEnumerator];
                while ((familyMemberArray = [familyMemberArraysEnum nextObject])) {
                    NSString *familyMemberFaceName = [familyMemberArray objectAtIndex:1];
                    if ([familyMemberFaceName compare:faceName options:NSCaseInsensitiveSearch] == NSOrderedSame) {
                        NSFontTraitMask traits = [[familyMemberArray objectAtIndex:3] integerValue];
                        NSInteger weight = [[familyMemberArray objectAtIndex:2] integerValue];
                        font = [fontManager fontWithFamily:familyName traits:traits weight:weight size:size];
                        break;
                    }
                }
                if (!font) {
                    if (0 < [familyMemberArrays count]) {
                        NSArray *familyMemberArray = [familyMemberArrays objectAtIndex:0];
                        NSFontTraitMask traits = [[familyMemberArray objectAtIndex:3] integerValue];
                        NSInteger weight = [[familyMemberArray objectAtIndex:2] integerValue];
                        font = [fontManager fontWithFamily:familyName traits:traits weight:weight size:size];
                    }
                }
493
#endif
494
495
496
497
498
499
500
501
                break;
            } else {
                dividingSpaceRange = [familyName rangeOfString:@" " options:NSBackwardsSearch];
                dividingDashRange = [familyName rangeOfString:@"-" options:NSBackwardsSearch];
                dividingRange = (0 < dividingSpaceRange.length && 0 < dividingDashRange.length) ? (dividingSpaceRange.location > dividingDashRange.location ? dividingSpaceRange : dividingDashRange) : (0 < dividingSpaceRange.length ? dividingSpaceRange : dividingDashRange);
            }
        }
    }
502
503
504
505
506
507
508
509
510
511
512
513
514
#if PLATFORM(IOS)
    if (!font)
        font = [PlatformFontClass systemFontOfSize:size];
#else
    if (!font)
        font = [NSFont fontWithName:@"Times" size:size];
    if (!font)
        font = [NSFont userFontOfSize:size];
    if (!font)
        font = [fontManager convertFont:WebDefaultFont() toSize:size];
    if (!font)
        font = WebDefaultFont();
#endif
515
    [cache setObject:font forKey:fontName];
516

517
518
519
520
521
522
523
    return font;
}

+ (NSParagraphStyle *)defaultParagraphStyle
{
    static NSMutableParagraphStyle *defaultParagraphStyle = nil;
    if (!defaultParagraphStyle) {
524
        defaultParagraphStyle = [[PlatformNSParagraphStyle defaultParagraphStyle] mutableCopy];
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
        [defaultParagraphStyle setDefaultTabInterval:36];
        [defaultParagraphStyle setTabStops:[NSArray array]];
    }
    return defaultParagraphStyle;
}

- (NSArray *)_childrenForNode:(DOMNode *)node
{
    NSMutableArray *array = [NSMutableArray array];
    DOMNode *child = [node firstChild];
    while (child) {
        [array addObject:child];
        child = [child nextSibling];
    }
    return array;
}

- (DOMCSSStyleDeclaration *)_computedStyleForElement:(DOMElement *)element
{
    DOMDocument *document = [element ownerDocument];
    DOMCSSStyleDeclaration *result = nil;
    result = [_computedStylesForElements objectForKey:element];
    if (result) {
548
549
        if ([result isEqual:[NSNull null]])
            result = nil;
550
551
552
553
554
555
556
557
558
559
560
    } else {
        result = [document getComputedStyle:element pseudoElement:@""] ;
        [_computedStylesForElements setObject:(result ? (id)result : (id)[NSNull null]) forKey:element];
    }
    return result;
}

- (DOMCSSStyleDeclaration *)_specifiedStyleForElement:(DOMElement *)element
{
    DOMCSSStyleDeclaration *result = [_specifiedStylesForElements objectForKey:element];
    if (result) {
561
562
        if ([result isEqual:[NSNull null]])
            result = nil;
563
564
565
566
567
568
569
570
571
572
573
574
575
    } else {
        result = [element style];
        [_specifiedStylesForElements setObject:(result ? (id)result : (id)[NSNull null]) forKey:element];
    }
    return result;
}

- (NSString *)_computedStringForNode:(DOMNode *)node property:(NSString *)key
{
    NSString *result = nil;
    BOOL inherit = YES;
    DOMElement *element = (DOMElement *)node;    
    if (element && [element nodeType] == DOM_ELEMENT_NODE) {
576
577
        DOMCSSStyleDeclaration *computedStyle;
        DOMCSSStyleDeclaration *specifiedStyle;
578
579
580
581
582
583
584
585
586
        inherit = NO;
        if (!result && (computedStyle = [self _computedStyleForElement:element])) {
            DOMCSSPrimitiveValue *computedValue = (DOMCSSPrimitiveValue *)[computedStyle getPropertyCSSValue:key];
            if (computedValue) {
                unsigned short valueType = [computedValue cssValueType];
                if (valueType == DOM_CSS_PRIMITIVE_VALUE) {
                    unsigned short primitiveType = [computedValue primitiveType];
                    if (primitiveType == DOM_CSS_STRING || primitiveType == DOM_CSS_URI || primitiveType == DOM_CSS_IDENT || primitiveType == DOM_CSS_ATTR) {
                        result = [computedValue getStringValue];
587
588
                        if (result && ![result length])
                            result = nil;
589
                    }
590
                } else if (valueType == DOM_CSS_VALUE_LIST)
591
592
593
594
595
596
597
598
599
600
601
                    result = [computedStyle getPropertyValue:key];
            }
        }
        if (!result && (specifiedStyle = [self _specifiedStyleForElement:element])) {
            DOMCSSPrimitiveValue *specifiedValue = (DOMCSSPrimitiveValue *)[specifiedStyle getPropertyCSSValue:key];
            if (specifiedValue) {
                unsigned short valueType = [specifiedValue cssValueType];
                if (valueType == DOM_CSS_PRIMITIVE_VALUE) {
                    unsigned short primitiveType = [specifiedValue primitiveType];
                    if (primitiveType == DOM_CSS_STRING || primitiveType == DOM_CSS_URI || primitiveType == DOM_CSS_IDENT || primitiveType == DOM_CSS_ATTR) {
                        result = [specifiedValue getStringValue];
602
603
604
                        if (result && ![result length])
                            result = nil;
                        if (!result)
605
606
                            result = [specifiedStyle getPropertyValue:key];
                    }
607
                } else if (valueType == DOM_CSS_INHERIT)
608
                    inherit = YES;
609
                else if (valueType == DOM_CSS_VALUE_LIST)
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
                    result = [specifiedStyle getPropertyValue:key];
            }
        }
        if (!result) {
            Element* coreElement = core(element);
            if ([@"display" isEqualToString:key]) {
                if (coreElement->hasTagName(headTag) || coreElement->hasTagName(scriptTag) || coreElement->hasTagName(appletTag) || coreElement->hasTagName(noframesTag))
                    result = @"none";
                else if (coreElement->hasTagName(addressTag) || coreElement->hasTagName(blockquoteTag) || coreElement->hasTagName(bodyTag) || coreElement->hasTagName(centerTag)
                         || coreElement->hasTagName(ddTag) || coreElement->hasTagName(dirTag) || coreElement->hasTagName(divTag) || coreElement->hasTagName(dlTag)
                         || coreElement->hasTagName(dtTag) || coreElement->hasTagName(fieldsetTag) || coreElement->hasTagName(formTag) || coreElement->hasTagName(frameTag)
                         || coreElement->hasTagName(framesetTag) || coreElement->hasTagName(hrTag) || coreElement->hasTagName(htmlTag) || coreElement->hasTagName(h1Tag)
                         || coreElement->hasTagName(h2Tag) || coreElement->hasTagName(h3Tag) || coreElement->hasTagName(h4Tag) || coreElement->hasTagName(h5Tag)
                         || coreElement->hasTagName(h6Tag) || coreElement->hasTagName(iframeTag) || coreElement->hasTagName(menuTag) || coreElement->hasTagName(noscriptTag)
                         || coreElement->hasTagName(olTag) || coreElement->hasTagName(pTag) || coreElement->hasTagName(preTag) || coreElement->hasTagName(ulTag))
                    result = @"block";
                else if (coreElement->hasTagName(liTag))
                    result = @"list-item";
628
                else if (coreElement->hasTagName(tableTag))
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
                    result = @"table";
                else if (coreElement->hasTagName(trTag))
                    result = @"table-row";
                else if (coreElement->hasTagName(thTag) || coreElement->hasTagName(tdTag))
                    result = @"table-cell";
                else if (coreElement->hasTagName(theadTag))
                    result = @"table-header-group";
                else if (coreElement->hasTagName(tbodyTag))
                    result = @"table-row-group";
                else if (coreElement->hasTagName(tfootTag))
                    result = @"table-footer-group";
                else if (coreElement->hasTagName(colTag))
                    result = @"table-column";
                else if (coreElement->hasTagName(colgroupTag))
                    result = @"table-column-group";
                else if (coreElement->hasTagName(captionTag))
                    result = @"table-caption";
            } else if ([@"white-space" isEqualToString:key]) {
                if (coreElement->hasTagName(preTag))
                    result = @"pre";
                else
                    inherit = YES;
            } else if ([@"font-style" isEqualToString:key]) {
                if (coreElement->hasTagName(iTag) || coreElement->hasTagName(citeTag) || coreElement->hasTagName(emTag) || coreElement->hasTagName(varTag) || coreElement->hasTagName(addressTag))
                    result = @"italic";
                else
                    inherit = YES;
            } else if ([@"font-weight" isEqualToString:key]) {
                if (coreElement->hasTagName(bTag) || coreElement->hasTagName(strongTag) || coreElement->hasTagName(thTag))
                    result = @"bolder";
                else
                    inherit = YES;
            } else if ([@"text-decoration" isEqualToString:key]) {
                if (coreElement->hasTagName(uTag) || coreElement->hasTagName(insTag))
                    result = @"underline";
                else if (coreElement->hasTagName(sTag) || coreElement->hasTagName(strikeTag) || coreElement->hasTagName(delTag))
                    result = @"line-through";
                else
                    inherit = YES; // ??? this is not strictly correct
            } else if ([@"text-align" isEqualToString:key]) {
                if (coreElement->hasTagName(centerTag) || coreElement->hasTagName(captionTag) || coreElement->hasTagName(thTag))
                    result = @"center";
                else
                    inherit = YES;
            } else if ([@"vertical-align" isEqualToString:key]) {
                if (coreElement->hasTagName(supTag))
                    result = @"super";
                else if (coreElement->hasTagName(subTag))
                    result = @"sub";
                else if (coreElement->hasTagName(theadTag) || coreElement->hasTagName(tbodyTag) || coreElement->hasTagName(tfootTag))
                    result = @"middle";
                else if (coreElement->hasTagName(trTag) || coreElement->hasTagName(thTag) || coreElement->hasTagName(tdTag))
                    inherit = YES;
            } else if ([@"font-family" isEqualToString:key] || [@"font-variant" isEqualToString:key] || [@"font-effect" isEqualToString:key]
                       || [@"text-transform" isEqualToString:key] || [@"text-shadow" isEqualToString:key] || [@"visibility" isEqualToString:key]
                       || [@"border-collapse" isEqualToString:key] || [@"empty-cells" isEqualToString:key] || [@"word-spacing" isEqualToString:key]
                       || [@"list-style-type" isEqualToString:key] || [@"direction" isEqualToString:key]) {
                inherit = YES;
            }
        }
    }
    if (!result && inherit) {
        DOMNode *parentNode = [node parentNode];
692
693
        if (parentNode)
            result = [self _stringForNode:parentNode property:key];
694
695
696
697
698
699
700
    }
    return result ? [result lowercaseString] : nil;
}

- (NSString *)_stringForNode:(DOMNode *)node property:(NSString *)key
{
    NSString *result = nil;
701
    RetainPtr<NSMutableDictionary> attributeDictionary = [_stringsForNodes objectForKey:node];
702
    if (!attributeDictionary) {
703
704
        attributeDictionary = adoptNS([[NSMutableDictionary alloc] init]);
        [_stringsForNodes setObject:attributeDictionary.get() forKey:node];
705
706
707
    }
    result = [attributeDictionary objectForKey:key];
    if (result) {
708
709
        if ([result isEqualToString:@""])
            result = nil;
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
    } else {
        result = [self _computedStringForNode:node property:key];
        [attributeDictionary setObject:(result ? result : @"") forKey:key];
    }
    return result;
}

static inline BOOL _getFloat(DOMCSSPrimitiveValue *primitiveValue, CGFloat *val)
{
    if (!val)
        return NO;
    switch ([primitiveValue primitiveType]) {
        case DOM_CSS_PX:
            *val = [primitiveValue getFloatValue:DOM_CSS_PX];
            return YES;
        case DOM_CSS_PT:
            *val = 4 * [primitiveValue getFloatValue:DOM_CSS_PT] / 3;
            return YES;
        case DOM_CSS_PC:
            *val = 16 * [primitiveValue getFloatValue:DOM_CSS_PC];
            return YES;
        case DOM_CSS_CM:
            *val = 96 * [primitiveValue getFloatValue:DOM_CSS_CM] / (CGFloat)2.54;
            return YES;
        case DOM_CSS_MM:
            *val = 96 * [primitiveValue getFloatValue:DOM_CSS_MM] / (CGFloat)25.4;
            return YES;
        case DOM_CSS_IN:
            *val = 96 * [primitiveValue getFloatValue:DOM_CSS_IN];
            return YES;
        default:
            return NO;
    }
}

- (BOOL)_getComputedFloat:(CGFloat *)val forNode:(DOMNode *)node property:(NSString *)key
{
747
748
    BOOL result = NO;
    BOOL inherit = YES;
749
750
751
752
753
754
755
    CGFloat floatVal = 0;
    DOMElement *element = (DOMElement *)node;    
    if (element && [element nodeType] == DOM_ELEMENT_NODE) {
        DOMCSSStyleDeclaration *computedStyle, *specifiedStyle;
        inherit = NO;
        if (!result && (computedStyle = [self _computedStyleForElement:element])) {
            DOMCSSPrimitiveValue *computedValue = (DOMCSSPrimitiveValue *)[computedStyle getPropertyCSSValue:key];
756
            if (computedValue && [computedValue cssValueType] == DOM_CSS_PRIMITIVE_VALUE)
757
758
759
760
761
762
                result = _getFloat(computedValue, &floatVal);
        }
        if (!result && (specifiedStyle = [self _specifiedStyleForElement:element])) {
            DOMCSSPrimitiveValue *specifiedValue = (DOMCSSPrimitiveValue *)[specifiedStyle getPropertyCSSValue:key];
            if (specifiedValue) {
                unsigned short valueType = [specifiedValue cssValueType];
763
                if (valueType == DOM_CSS_PRIMITIVE_VALUE)
764
                    result = _getFloat(specifiedValue, &floatVal);
765
                else if (valueType == DOM_CSS_INHERIT)
766
767
768
769
770
771
772
773
774
775
776
                    inherit = YES;
            }
        }
        if (!result) {
            if ([@"text-indent" isEqualToString:key] || [@"letter-spacing" isEqualToString:key] || [@"word-spacing" isEqualToString:key]
                || [@"line-height" isEqualToString:key] || [@"widows" isEqualToString:key] || [@"orphans" isEqualToString:key])
                inherit = YES;
        }
    }
    if (!result && inherit) {
        DOMNode *parentNode = [node parentNode];
777
778
        if (parentNode)
            result = [self _getFloat:&floatVal forNode:parentNode property:key];
779
780
781
782
783
784
785
786
787
788
789
    }
    if (result && val)
        *val = floatVal;
    return result;
}

- (BOOL)_getFloat:(CGFloat *)val forNode:(DOMNode *)node property:(NSString *)key
{
    BOOL result = NO;
    CGFloat floatVal = 0;
    NSNumber *floatNumber;
790
    RetainPtr<NSMutableDictionary> attributeDictionary = [_floatsForNodes objectForKey:node];
791
792
    if (!attributeDictionary) {
        attributeDictionary = [[NSMutableDictionary alloc] init];
793
        [_floatsForNodes setObject:attributeDictionary.get() forKey:node];
794
795
796
797
798
799
800
801
802
803
804
    }
    floatNumber = [attributeDictionary objectForKey:key];
    if (floatNumber) {
        if (![[NSNull null] isEqual:floatNumber]) {
            result = YES;
            floatVal = [floatNumber floatValue];
        }
    } else {
        result = [self _getComputedFloat:&floatVal forNode:node property:key];
        [attributeDictionary setObject:(result ? (id)[NSNumber numberWithDouble:floatVal] : (id)[NSNull null]) forKey:key];
    }
805
806
    if (result && val)
        *val = floatVal;
807
808
809
    return result;
}

810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
static NSString *_NSFirstPathForDirectoriesInDomains(NSSearchPathDirectory directory, NSSearchPathDomainMask domainMask, BOOL expandTilde)
{
    NSArray *array = NSSearchPathForDirectoriesInDomains(directory, domainMask, expandTilde);
    return [array count] >= 1 ? [array objectAtIndex:0] : nil;
}

static NSString *_NSSystemLibraryPath(void)
{
    return _NSFirstPathForDirectoriesInDomains(NSLibraryDirectory, NSSystemDomainMask, YES);
}

- (NSBundle *)_webKitBundle
{
    NSBundle *bundle = [NSBundle bundleWithIdentifier:@"com.apple.WebKit"];
    if (!bundle)
        bundle = [NSBundle bundleWithPath:[_NSSystemLibraryPath() stringByAppendingPathComponent:@"Frameworks/WebKit.framework"]];
    return bundle;
}

#if PLATFORM(IOS)
static inline UIColor *_colorForRGBColor(DOMRGBColor *domRGBColor, BOOL)
{
    return [getUIColorClass() _disambiguated_due_to_CIImage_colorWithCGColor:[domRGBColor color]];
}

#else
836
837
838
839
840
841
842
843
844
845
static inline NSColor *_colorForRGBColor(DOMRGBColor *domRGBColor, BOOL ignoreBlack)
{
    NSColor *color = [domRGBColor _color];
    NSColorSpace *colorSpace = [color colorSpace];
    const CGFloat ColorEpsilon = 1 / (2 * (CGFloat)255.0);
    
    if (color) {
        if ([colorSpace isEqual:[NSColorSpace genericGrayColorSpace]] || [colorSpace isEqual:[NSColorSpace deviceGrayColorSpace]]) {
            CGFloat white, alpha;
            [color getWhite:&white alpha:&alpha];
846
847
            if (white < ColorEpsilon && (ignoreBlack || alpha < ColorEpsilon))
                color = nil;
848
849
        } else {
            NSColor *rgbColor = nil;
850
851
852
853
            if ([colorSpace isEqual:[NSColorSpace genericRGBColorSpace]] || [colorSpace isEqual:[NSColorSpace deviceRGBColorSpace]])
                rgbColor = color;
            if (!rgbColor)
                rgbColor = [color colorUsingColorSpaceName:NSDeviceRGBColorSpace];
854
855
856
            if (rgbColor) {
                CGFloat red, green, blue, alpha;
                [rgbColor getRed:&red green:&green blue:&blue alpha:&alpha];
857
858
                if (red < ColorEpsilon && green < ColorEpsilon && blue < ColorEpsilon && (ignoreBlack || alpha < ColorEpsilon))
                    color = nil;
859
860
861
862
863
            }
        }
    }
    return color;
}
864
#endif
865
866
867
868
869

static inline NSShadow *_shadowForShadowStyle(NSString *shadowStyle)
{
    NSShadow *shadow = nil;
    NSUInteger shadowStyleLength = [shadowStyle length];
870
871
872
873
874
875
    NSRange openParenRange = [shadowStyle rangeOfString:@"("];
    NSRange closeParenRange = [shadowStyle rangeOfString:@")"];
    NSRange firstRange = NSMakeRange(NSNotFound, 0);
    NSRange secondRange = NSMakeRange(NSNotFound, 0);
    NSRange thirdRange = NSMakeRange(NSNotFound, 0);
    NSRange spaceRange;
876
877
878
    if (openParenRange.length > 0 && closeParenRange.length > 0 && NSMaxRange(openParenRange) < closeParenRange.location) {
        NSArray *components = [[shadowStyle substringWithRange:NSMakeRange(NSMaxRange(openParenRange), closeParenRange.location - NSMaxRange(openParenRange))] componentsSeparatedByString:@","];
        if ([components count] >= 3) {
879
880
881
882
883
            CGFloat red = [[components objectAtIndex:0] floatValue] / 255;
            CGFloat green = [[components objectAtIndex:1] floatValue] / 255;
            CGFloat blue = [[components objectAtIndex:2] floatValue] / 255;
            CGFloat alpha = ([components count] >= 4) ? [[components objectAtIndex:3] floatValue] / 255 : 1;
            NSColor *shadowColor = [PlatformColorClass colorWithCalibratedRed:red green:green blue:blue alpha:alpha];
884
885
886
            NSSize shadowOffset;
            CGFloat shadowBlurRadius;
            firstRange = [shadowStyle rangeOfString:@"px"];
887
888
889
890
            if (firstRange.length > 0 && NSMaxRange(firstRange) < shadowStyleLength)
                secondRange = [shadowStyle rangeOfString:@"px" options:0 range:NSMakeRange(NSMaxRange(firstRange), shadowStyleLength - NSMaxRange(firstRange))];
            if (secondRange.length > 0 && NSMaxRange(secondRange) < shadowStyleLength)
                thirdRange = [shadowStyle rangeOfString:@"px" options:0 range:NSMakeRange(NSMaxRange(secondRange), shadowStyleLength - NSMaxRange(secondRange))];
891
892
            if (firstRange.location > 0 && firstRange.length > 0 && secondRange.length > 0 && thirdRange.length > 0) {
                spaceRange = [shadowStyle rangeOfString:@" " options:NSBackwardsSearch range:NSMakeRange(0, firstRange.location)];
893
894
                if (spaceRange.length == 0)
                    spaceRange = NSMakeRange(0, 0);
895
896
                shadowOffset.width = [[shadowStyle substringWithRange:NSMakeRange(NSMaxRange(spaceRange), firstRange.location - NSMaxRange(spaceRange))] floatValue];
                spaceRange = [shadowStyle rangeOfString:@" " options:NSBackwardsSearch range:NSMakeRange(0, secondRange.location)];
897
898
899
900
901
902
903
904
905
                if (!spaceRange.length)
                    spaceRange = NSMakeRange(0, 0);
                CGFloat shadowHeight = [[shadowStyle substringWithRange:NSMakeRange(NSMaxRange(spaceRange), secondRange.location - NSMaxRange(spaceRange))] floatValue];
                // I don't know why we have this difference between the two platforms.
#if PLATFORM(IOS)
                shadowOffset.height = shadowHeight;
#else
                shadowOffset.height = -shadowHeight;
#endif
906
                spaceRange = [shadowStyle rangeOfString:@" " options:NSBackwardsSearch range:NSMakeRange(0, thirdRange.location)];
907
908
                if (!spaceRange.length)
                    spaceRange = NSMakeRange(0, 0);
909
                shadowBlurRadius = [[shadowStyle substringWithRange:NSMakeRange(NSMaxRange(spaceRange), thirdRange.location - NSMaxRange(spaceRange))] floatValue];
910
                shadow = [[[PlatformNSShadow alloc] init] autorelease];
911
912
913
914
915
916
917
918
919
920
921
922
923
924
                [shadow setShadowColor:shadowColor];
                [shadow setShadowOffset:shadowOffset];
                [shadow setShadowBlurRadius:shadowBlurRadius];
            }
        }
    }
    return shadow;
}

- (BOOL)_elementIsBlockLevel:(DOMElement *)element
{
    BOOL isBlockLevel = NO;
    NSNumber *val = nil;
    val = [_elementIsBlockLevel objectForKey:element];
925
    if (val)
926
        isBlockLevel = [val boolValue];
927
928
929
930
    else {
        NSString *displayVal = [self _stringForNode:element property:@"display"];
        NSString *floatVal = [self _stringForNode:element property:@"float"];
        if (floatVal && ([@"left" isEqualToString:floatVal] || [@"right" isEqualToString:floatVal]))
931
            isBlockLevel = YES;
932
        else if (displayVal)
933
            isBlockLevel = ([@"block" isEqualToString:displayVal] || [@"list-item" isEqualToString:displayVal] || [displayVal hasPrefix:@"table"]);
934

935
936
937
938
939
940
941
        [_elementIsBlockLevel setObject:[NSNumber numberWithBool:isBlockLevel] forKey:element];
    }
    return isBlockLevel;
}

- (BOOL)_elementHasOwnBackgroundColor:(DOMElement *)element
{
942
943
    // In the text system, text blocks (table elements) and documents (body elements)
    // have their own background colors, which should not be inherited.
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
    if ([self _elementIsBlockLevel:element]) {
        Element* coreElement = core(element);
        NSString *displayVal = [self _stringForNode:element property:@"display"];
        if (coreElement->hasTagName(htmlTag) || coreElement->hasTagName(bodyTag) || [displayVal hasPrefix:@"table"])
            return YES;
    }
    return NO;
}
    
- (DOMElement *)_blockLevelElementForNode:(DOMNode *)node
{
    DOMElement *element = (DOMElement *)node;
    while (element && [element nodeType] != DOM_ELEMENT_NODE)
        element = (DOMElement *)[element parentNode];
    if (element && ![self _elementIsBlockLevel:element])
        element = [self _blockLevelElementForNode:[element parentNode]];
    return element;
}

963
- (PlatformColor *)_computedColorForNode:(DOMNode *)node property:(NSString *)key
964
{
965
966
967
968
969
    PlatformColor *result = nil;
    BOOL inherit = YES;
    BOOL haveResult = NO;
    BOOL isColor = [@"color" isEqualToString:key];
    BOOL isBackgroundColor = [@"background-color" isEqualToString:key];
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
    DOMElement *element = (DOMElement *)node;    
    if (element && [element nodeType] == DOM_ELEMENT_NODE) {
        DOMCSSStyleDeclaration *computedStyle, *specifiedStyle;
        inherit = NO;
        if (!haveResult && (computedStyle = [self _computedStyleForElement:element])) {
            DOMCSSPrimitiveValue *computedValue = (DOMCSSPrimitiveValue *)[computedStyle getPropertyCSSValue:key];
            if (computedValue && [computedValue cssValueType] == DOM_CSS_PRIMITIVE_VALUE && [computedValue primitiveType] == DOM_CSS_RGBCOLOR) {
                result = _colorForRGBColor([computedValue getRGBColorValue], isColor);
                haveResult = YES;
            }
        }
        if (!haveResult && (specifiedStyle = [self _specifiedStyleForElement:element])) {
            DOMCSSPrimitiveValue *specifiedValue = (DOMCSSPrimitiveValue *)[specifiedStyle getPropertyCSSValue:key];
            if (specifiedValue) {
                unsigned short valueType = [specifiedValue cssValueType];
                if (valueType == DOM_CSS_PRIMITIVE_VALUE && [specifiedValue primitiveType] == DOM_CSS_RGBCOLOR) {
                    result = _colorForRGBColor([specifiedValue getRGBColorValue], isColor);
                    haveResult = YES;
988
                } else if (valueType == DOM_CSS_INHERIT)
989
990
991
992
                    inherit = YES;
            }
        }
        if (!result) {
993
994
            if ((isColor && !haveResult) || (isBackgroundColor && ![self _elementHasOwnBackgroundColor:element]))
                inherit = YES;
995
996
997
998
        }
    }
    if (!result && inherit) {
        DOMNode *parentNode = [node parentNode];
999
        if (parentNode && !(isBackgroundColor && [parentNode nodeType] == DOM_ELEMENT_NODE && [self _elementHasOwnBackgroundColor:(DOMElement *)parentNode]))
1000
1001
1002
1003
1004
            result = [self _colorForNode:parentNode property:key];
    }
    return result;
}

1005
1006
- (PlatformColor *)_colorForNode:(DOMNode *)node property:(NSString *)key {
    RetainPtr<NSMutableDictionary> attributeDictionary = [_colorsForNodes objectForKey:node];
1007
    if (!attributeDictionary) {
1008
1009
        attributeDictionary = adoptNS([[NSMutableDictionary alloc] init]);
        [_colorsForNodes setObject:attributeDictionary.get() forKey:node];
1010
    }
1011
1012
    PlatformColor *result = [attributeDictionary objectForKey:key];
    if (!result) {
1013
        result = [self _computedColorForNode:node property:key];
1014
        [attributeDictionary setObject:(result ? result : [PlatformColorClass clearColor]) forKey:key];
1015
    }
1016
1017
    if ([[PlatformColorClass clearColor] isEqual:result] || ([result alphaComponent] == 0.0) )
        result = nil;
1018
1019
1020
    return result;
}

1021
1022
#define UIFloatIsZero(number) (fabs(number - 0) < FLT_EPSILON)

1023
1024
1025
1026
- (NSDictionary *)_computedAttributesForElement:(DOMElement *)element
{
    DOMElement *blockElement = [self _blockLevelElementForNode:element];
    NSMutableDictionary *attrs = [NSMutableDictionary dictionary];
1027
#if !PLATFORM(IOS)
1028
    NSFontManager *fontManager = [NSFontManager sharedFontManager];
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
#endif
    NSString *fontEffect = [self _stringForNode:element property:@"font-effect"];
    NSString *textDecoration = [self _stringForNode:element property:@"text-decoration"];
    NSString *verticalAlign = [self _stringForNode:element property:@"vertical-align"];
    NSString *textShadow = [self _stringForNode:element property:@"text-shadow"];
    NSString *fontLigatures = [self _stringForNode:element property:@"font-variant-ligatures"];
    NSString *fontKerning = [self _stringForNode:element property:@"font-kerning"];
    NSString *letterSpacing = [self _stringForNode:element property:@"letter-spacing"];
    CGFloat fontSize = 0;
    CGFloat baselineOffset = 0;
    CGFloat strokeWidth = 0.0;
    PlatformFont *font = nil;
    PlatformFont *actualFont = (PlatformFont *)[element _font];
    PlatformColor *foregroundColor = [self _colorForNode:element property:@"color"];
    PlatformColor *backgroundColor = [self _colorForNode:element property:@"background-color"];
    PlatformColor *strokeColor = [self _colorForNode:element property:@"-webkit-text-stroke-color"];

    if (![self _getFloat:&fontSize forNode:element property:@"font-size"] || fontSize <= 0.0)
        fontSize = _defaultFontSize;
1048
1049
    fontSize *= _textSizeMultiplier;
    if (fontSize < _minimumFontSize) fontSize = _minimumFontSize;
1050
    if (fabs(floor(2.0 * fontSize + 0.5) / 2.0 - fontSize) < 0.05)
1051
        fontSize = (CGFloat)floor(2.0 * fontSize + 0.5) / 2;
1052
    else if (fabs(floor(10.0 * fontSize + 0.5) / 10.0 - fontSize) < 0.005)
1053
        fontSize = (CGFloat)floor(10.0 * fontSize + 0.5) / 10;
1054
1055
1056

    if (fontSize <= 0.0)
        fontSize = 12;
1057
    
1058
1059
1060
1061
1062
1063
1064
#if PLATFORM(IOS)
    if (actualFont)
        font = [actualFont fontWithSize:fontSize];
#else
    if (actualFont)
        font = [fontManager convertFont:actualFont toSize:fontSize];
#endif
1065
    if (!font) {
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
        NSString *fontName = [[self _stringForNode:element property:@"font-family"] capitalizedString];
        NSString *fontStyle = [self _stringForNode:element property:@"font-style"];
        NSString *fontWeight = [self _stringForNode:element property:@"font-weight"];
#if !PLATFORM(IOS)
        NSString *fontVariant = [self _stringForNode:element property:@"font-variant"];
#endif
        if (!fontName)
            fontName = _standardFontFamily;
        if (fontName)
            font = _fontForNameAndSize(fontName, fontSize, _fontCache);
        if (!font)
            font = [PlatformFontClass fontWithName:@"Times" size:fontSize];
1078
        if ([@"italic" isEqualToString:fontStyle] || [@"oblique" isEqualToString:fontStyle]) {
1079
1080
1081
1082
            PlatformFont *originalFont = font;
#if PLATFORM(IOS)
            font = [PlatformFontClass fontWithFamilyName:[font familyName] traits:UIFontTraitItalic size:[font pointSize]];
#else
1083
            font = [fontManager convertFont:font toHaveTrait:NSItalicFontMask];
1084
1085
1086
#endif
            if (!font)
                font = originalFont;
1087
1088
1089
        }
        if ([fontWeight hasPrefix:@"bold"] || [fontWeight integerValue] >= 700) {
            // ??? handle weight properly using NSFontManager
1090
1091
1092
1093
            PlatformFont *originalFont = font;
#if PLATFORM(IOS)
            font = [PlatformFontClass fontWithFamilyName:[font familyName] traits:UIFontTraitBold size:[font pointSize]];
#else
1094
            font = [fontManager convertFont:font toHaveTrait:NSBoldFontMask];
1095
1096
1097
#endif
            if (!font)
                font = originalFont;
1098
        }
1099
#if !PLATFORM(IOS) // IJB: No small caps support on iOS
1100
1101
1102
1103
        if ([@"small-caps" isEqualToString:fontVariant]) {
            // ??? synthesize small-caps if [font isEqual:originalFont]
            NSFont *originalFont = font;
            font = [fontManager convertFont:font toHaveTrait:NSSmallCapsFontMask];
1104
1105
            if (!font)
                font = originalFont;
1106
        }
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
#endif
    }
    if (font)
        [attrs setObject:font forKey:NSFontAttributeName];
    if (foregroundColor)
        [attrs setObject:foregroundColor forKey:NSForegroundColorAttributeName];
    if (backgroundColor && ![self _elementHasOwnBackgroundColor:element])
        [attrs setObject:backgroundColor forKey:NSBackgroundColorAttributeName];

    if ([self _getFloat:&strokeWidth forNode:element property:@"-webkit-text-stroke-width"]) {
        float textStrokeWidth = strokeWidth / ([font pointSize] * 0.01);
        [attrs setObject:[NSNumber numberWithDouble:textStrokeWidth] forKey:NSStrokeWidthAttributeName];
1119
    }
1120
1121
    if(strokeColor)
        [attrs setObject:strokeColor forKey:NSStrokeColorAttributeName];
1122
    if (fontEffect) {
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
        if ([fontEffect rangeOfString:@"outline"].location != NSNotFound)
            [attrs setObject:[NSNumber numberWithDouble:3.0] forKey:NSStrokeWidthAttributeName];
        if ([fontEffect rangeOfString:@"emboss"].location != NSNotFound)
            [attrs setObject:[[[PlatformNSShadow alloc] init] autorelease] forKey:NSShadowAttributeName];
    }
    if (fontKerning || letterSpacing) {
        if ([fontEffect rangeOfString:@"none"].location != NSNotFound)
            [attrs setObject:@0.0 forKey:NSKernAttributeName];
        else {
            double kernVal = letterSpacing ? [letterSpacing doubleValue] : 0.0;
            if (UIFloatIsZero(kernVal))
                [attrs setObject:[NSNull null] forKey:NSKernAttributeName]; // auto and normal, the other possible values, are both "kerning enabled"
            else
                [attrs setObject:[NSNumber numberWithDouble:kernVal] forKey:NSKernAttributeName];
        }
    }
    if (fontLigatures) {
        if ([fontEffect rangeOfString:@"normal"].location != NSNotFound)
            ;   // default: whatever the system decides to do
        else if ([fontEffect rangeOfString:@"common-ligatures"].location != NSNotFound)
            [attrs setObject:@1 forKey:NSLigatureAttributeName];   // explicitly enabled
        else if ([fontEffect rangeOfString:@"no-common-ligatures"].location != NSNotFound)
            [attrs setObject:@0 forKey:NSLigatureAttributeName];  // explicitly disabled
1146
    }
1147

1148
    if (textDecoration && [textDecoration length] > 4) {
1149
1150
1151
1152
        if ([textDecoration rangeOfString:@"underline"].location != NSNotFound)
            [attrs setObject:[NSNumber numberWithInteger:NSUnderlineStyleSingle] forKey:NSUnderlineStyleAttributeName];
        if ([textDecoration rangeOfString:@"line-through"].location != NSNotFound)
            [attrs setObject:[NSNumber numberWithInteger:NSUnderlineStyleSingle] forKey:NSStrikethroughStyleAttributeName];
1153
1154
    }
    if (verticalAlign) {
1155
1156
1157
1158
        if ([verticalAlign rangeOfString:@"super"].location != NSNotFound)
            [attrs setObject:[NSNumber numberWithInteger:1] forKey:NSSuperscriptAttributeName];
        if ([verticalAlign rangeOfString:@"sub"].location != NSNotFound)
            [attrs setObject:[NSNumber numberWithInteger:-1] forKey:NSSuperscriptAttributeName];
1159
    }
1160
1161
    if ([self _getFloat:&baselineOffset forNode:element property:@"vertical-align"])
        [attrs setObject:[NSNumber numberWithDouble:baselineOffset] forKey:NSBaselineOffsetAttributeName];
1162
1163
    if (textShadow && [textShadow length] > 4) {
        NSShadow *shadow = _shadowForShadowStyle(textShadow);
1164
1165
        if (shadow)
            [attrs setObject:shadow forKey:NSShadowAttributeName];
1166
    }
1167
1168
    if (element != blockElement && [_writingDirectionArray count] > 0)
        [attrs setObject:[NSArray arrayWithArray:_writingDirectionArray] forKey:NSWritingDirectionAttributeName];
1169
1170
1171
1172
1173
    
    if (blockElement) {
        NSMutableParagraphStyle *paragraphStyle = [[[self class] defaultParagraphStyle] mutableCopy];
        NSString *blockTag = [blockElement tagName];
        BOOL isParagraph = ([@"P" isEqualToString:blockTag] || [@"LI" isEqualToString:blockTag] || ([blockTag hasPrefix:@"H"] && 2 == [blockTag length]));
1174
1175
1176
1177
1178
1179
1180
1181
        NSString *textAlign = [self _stringForNode:blockElement property:@"text-align"];
        NSString *direction = [self _stringForNode:blockElement property:@"direction"];
        NSString *hyphenation = [self _stringForNode:blockElement property:@"-webkit-hyphens"];
        CGFloat leftMargin = 0;
        CGFloat rightMargin = 0;
        CGFloat bottomMargin = 0;
        CGFloat textIndent = 0;
        CGFloat lineHeight = 0;
1182
1183
        if (textAlign) {
            // WebKit can return -khtml-left, -khtml-right, -khtml-center
1184
1185
1186
1187
1188
1189
1190
1191
            if ([textAlign hasSuffix:@"left"])
                [paragraphStyle setAlignment:NSTextAlignmentLeft];
            else if ([textAlign hasSuffix:@"right"])
                [paragraphStyle setAlignment:NSTextAlignmentRight];
            else if ([textAlign hasSuffix:@"center"])
                [paragraphStyle setAlignment:NSTextAlignmentCenter];
            else if ([textAlign hasSuffix:@"justify"])
                [paragraphStyle setAlignment:NSTextAlignmentJustified];
1192
1193
        }
        if (direction) {
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
            if ([direction isEqualToString:@"ltr"])
                [paragraphStyle setBaseWritingDirection:NSWritingDirectionLeftToRight];
            else if ([direction isEqualToString:@"rtl"])
                [paragraphStyle setBaseWritingDirection:NSWritingDirectionRightToLeft];
        }
        if(hyphenation) {
            if ([hyphenation isEqualToString:@"auto"])
                [paragraphStyle setHyphenationFactor:1.0];
            else
                [paragraphStyle setHyphenationFactor:0.0];
1204
1205
1206
        }
        if ([blockTag hasPrefix:@"H"] && 2 == [blockTag length]) {
            NSInteger headerLevel = [blockTag characterAtIndex:1] - '0';
1207
1208
            if (1 <= headerLevel && headerLevel <= 6)
                [paragraphStyle setHeaderLevel:headerLevel];
1209
1210
        }
        if (isParagraph) {
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
            if ([self _getFloat:&leftMargin forNode:blockElement property:@"margin-left"] && leftMargin > 0.0)
                [paragraphStyle setHeadIndent:leftMargin];
            if ([self _getFloat:&textIndent forNode:blockElement property:@"text-indent"])
                [paragraphStyle setFirstLineHeadIndent:[paragraphStyle headIndent] + textIndent];
            if ([self _getFloat:&rightMargin forNode:blockElement property:@"margin-right"] && rightMargin > 0.0)
                [paragraphStyle setTailIndent:-rightMargin];
            if ([self _getFloat:&bottomMargin forNode:blockElement property:@"margin-bottom"] && bottomMargin > 0.0)
                [paragraphStyle setParagraphSpacing:bottomMargin];
        }
        if (_webViewTextSizeMultiplier > 0.0 && [self _getFloat:&lineHeight forNode:element property:@"line-height"] && lineHeight > 0.0)
1221
            [paragraphStyle setMinimumLineHeight:lineHeight / _webViewTextSizeMultiplier];
1222
1223
1224
1225
        if ([_textLists count] > 0)
            [paragraphStyle setTextLists:_textLists];
        if ([_textBlocks count] > 0)
            [paragraphStyle setTextBlocks:_textBlocks];
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
        [attrs setObject:paragraphStyle forKey:NSParagraphStyleAttributeName];
        [paragraphStyle release];
    }
    return attrs;
}

- (NSDictionary *)_attributesForElement:(DOMElement *)element
{
    NSDictionary *result;
    if (element) {
        result = [_attributesForElements objectForKey:element];
        if (!result) {
            result = [self _computedAttributesForElement:element];
            [_attributesForElements setObject:result forKey:element];
        }
1241
    } else
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
        result = [NSDictionary dictionary];
    return result;

}

- (void)_newParagraphForElement:(DOMElement *)element tag:(NSString *)tag allowEmpty:(BOOL)flag suppressTrailingSpace:(BOOL)suppress
{
    NSUInteger textLength = [_attrStr length];
    unichar lastChar = (textLength > 0) ? [[_attrStr string] characterAtIndex:textLength - 1] : '\n';
    NSRange rangeToReplace = (suppress && _flags.isSoft && (lastChar == ' ' || lastChar == NSLineSeparatorCharacter)) ? NSMakeRange(textLength - 1, 1) : NSMakeRange(textLength, 0);
    BOOL needBreak = (flag || lastChar != '\n');
    if (needBreak) {
        NSString *string = (([@"BODY" isEqualToString:tag] || [@"HTML" isEqualToString:tag]) ? @"" : @"\n");
        [_writingDirectionArray removeAllObjects];
        [_attrStr replaceCharactersInRange:rangeToReplace withString:string];
1257
1258
        if (rangeToReplace.location < _domRangeStartIndex)
            _domRangeStartIndex += [string length] - rangeToReplace.length;
1259
1260
1261
        rangeToReplace.length = [string length];
        if (!_flags.isIndexing) {
            NSDictionary *attrs = [self _attributesForElement:element];
1262
1263
            if (!_flags.isTesting && rangeToReplace.length > 0)
                [_attrStr setAttributes:attrs range:rangeToReplace];
1264
1265
1266
1267
1268
1269
1270
1271
        }
        _flags.isSoft = YES;
    }
}

- (void)_newLineForElement:(DOMElement *)element
{
    unichar c = NSLineSeparatorCharacter;
1272
    RetainPtr<NSString> string = adoptNS([[NSString alloc] initWithCharacters:&c length:1]);
1273
1274
    NSUInteger textLength = [_attrStr length];
    NSRange rangeToReplace = NSMakeRange(textLength, 0);
1275
    [_attrStr replaceCharactersInRange:rangeToReplace withString:string.get()];
1276
1277
1278
1279
    rangeToReplace.length = [string length];
    if (rangeToReplace.location < _domRangeStartIndex) _domRangeStartIndex += rangeToReplace.length;
    if (!_flags.isIndexing) {
        NSDictionary *attrs = [self _attributesForElement:element];
1280
1281
        if (!_flags.isTesting && rangeToReplace.length > 0)
            [_attrStr setAttributes:attrs range:rangeToReplace];
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
    }
    _flags.isSoft = YES;
}

- (void)_newTabForElement:(DOMElement *)element
{
    NSString *string = @"\t";
    NSUInteger textLength = [_attrStr length];
    unichar lastChar = (textLength > 0) ? [[_attrStr string] characterAtIndex:textLength - 1] : '\n';
    NSRange rangeToReplace = (_flags.isSoft && lastChar == ' ') ? NSMakeRange(textLength - 1, 1) : NSMakeRange(textLength, 0);
    [_attrStr replaceCharactersInRange:rangeToReplace withString:string];
    rangeToReplace.length = [string length];
1294
1295
    if (rangeToReplace.location < _domRangeStartIndex)
        _domRangeStartIndex += rangeToReplace.length;
1296
1297
    if (!_flags.isIndexing) {
        NSDictionary *attrs = [self _attributesForElement:element];
1298
1299
        if (!_flags.isTesting && rangeToReplace.length > 0)
            [_attrStr setAttributes:attrs range:rangeToReplace];
1300
1301
1302
    }
    _flags.isSoft = YES;
}
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317

- (Class)_WebMessageDocumentClass
{
    static Class _WebMessageDocumentClass = Nil;
    static BOOL lookedUpClass = NO;
    if (!lookedUpClass) {
        // If the class is not there, we don't want to try again
        _WebMessageDocumentClass = objc_lookUpClass("MFWebMessageDocument");
        if (_WebMessageDocumentClass && ![_WebMessageDocumentClass respondsToSelector:@selector(document:attachment:forURL:)])
            _WebMessageDocumentClass = Nil;
        lookedUpClass = YES;
    }
    return _WebMessageDocumentClass;
}

1318
1319
1320
1321
1322
- (BOOL)_addAttachmentForElement:(DOMElement *)element URL:(NSURL *)url needsParagraph:(BOOL)needsParagraph usePlaceholder:(BOOL)flag
{
    BOOL retval = NO, notFound = NO;
    NSFileWrapper *fileWrapper = nil;
    Frame* frame = core([element ownerDocument])->frame();
1323
    DocumentLoader *dataSource = frame->loader().frameHasLoaded() ? frame->loader().documentLoader() : 0;
1324
1325
    BOOL ignoreOrientation = YES;

1326
1327
    if (_flags.isIndexing)
        return NO;
1328
1329
    if ([url isFileURL]) {
        NSString *path = [[url path] stringByStandardizingPath];
1330
1331
        if (path)
            fileWrapper = [[[NSFileWrapper alloc] initWithURL:url options:0 error:NULL] autorelease];
1332
1333
1334
    }
    if (!fileWrapper) {
        RefPtr<ArchiveResource> resource = dataSource->subresource(url);
1335
1336
1337
1338
1339
1340
        if (!resource)
            resource = dataSource->subresource(url);

        const String& mimeType = resource->mimeType();
        if (flag && resource && mimeType == "text/html")
            notFound = YES;
1341
        if (resource && !notFound) {
1342
            fileWrapper = [[[NSFileWrapper alloc] initRegularFileWithContents:resource->data()->createNSData().get()] autorelease];
1343
            [fileWrapper setPreferredFilename:suggestedFilenameWithMIMEType(url, mimeType)];
1344
1345
        }
    }
1346
#if !PLATFORM(IOS)
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
    if (!fileWrapper && !notFound) {
        fileWrapper = fileWrapperForURL(dataSource, url);