⚠ Archived content — this site is no longer maintained.   Current WebKit documentation is at docs.webkit.org.

Changeset 197600 in webkit


Ignore:
Timestamp:
Mar 4, 2016, 4:57:19 PM (11 years ago)
Author:
timothy_horton@apple.com
Message:

Begin implementing <attachment> painting on iOS
​https://bugs.webkit.org/show_bug.cgi?id=155046
<rdar://problem/24805991>

Reviewed by Enrica Casucci.

No new tests; there are existing tests that I will unskip and rebaseline
in the near future.

  • rendering/RenderThemeIOS.h:
  • rendering/RenderThemeIOS.mm:

(WebCore::AttachmentInfo::addLine):
(WebCore::AttachmentInfo::buildTitleLines):
(WebCore::AttachmentInfo::buildSingleLine):
(WebCore::getAttachmentProgress):
(WebCore::iconForAttachment):
(WebCore::AttachmentInfo::AttachmentInfo):
(WebCore::RenderThemeIOS::attachmentIntrinsicSize):
(WebCore::RenderThemeIOS::attachmentBaseline):
(WebCore::paintAttachmentIcon):
(WebCore::paintAttachmentText):
(WebCore::paintAttachmentProgress):
(WebCore::paintAttachmentBorder):
(WebCore::RenderThemeIOS::paintAttachment):
There are still a few missing pieces, but get <attachment> painting a bit on iOS.
We will paint an icon, action, title, and subtitle - in that order - depending on what we have.
The content is vertically and horizontally centered.

Location:
trunk/Source/WebCore
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r197599 r197600  
     12016-03-04  Tim Horton  <timothy_horton@apple.com>
     2
     3        Begin implementing <attachment> painting on iOS
     4        https://bugs.webkit.org/show_bug.cgi?id=155046
     5        <rdar://problem/24805991>
     6
     7        Reviewed by Enrica Casucci.
     8
     9        No new tests; there are existing tests that I will unskip and rebaseline
     10        in the near future.
     11
     12        * rendering/RenderThemeIOS.h:
     13        * rendering/RenderThemeIOS.mm:
     14        (WebCore::AttachmentInfo::addLine):
     15        (WebCore::AttachmentInfo::buildTitleLines):
     16        (WebCore::AttachmentInfo::buildSingleLine):
     17        (WebCore::getAttachmentProgress):
     18        (WebCore::iconForAttachment):
     19        (WebCore::AttachmentInfo::AttachmentInfo):
     20        (WebCore::RenderThemeIOS::attachmentIntrinsicSize):
     21        (WebCore::RenderThemeIOS::attachmentBaseline):
     22        (WebCore::paintAttachmentIcon):
     23        (WebCore::paintAttachmentText):
     24        (WebCore::paintAttachmentProgress):
     25        (WebCore::paintAttachmentBorder):
     26        (WebCore::RenderThemeIOS::paintAttachment):
     27        There are still a few missing pieces, but get <attachment> painting a bit on iOS.
     28        We will paint an icon, action, title, and subtitle - in that order - depending on what we have.
     29        The content is vertically and horizontally centered.
     30
    1312016-03-04  Gavin Barraclough  <barraclough@apple.com>
    232
  • trunk/Source/WebCore/rendering/RenderThemeIOS.h

    r197563 r197600  
    3535class RenderStyle;
    3636class GraphicsContext;
    37    
     37struct AttachmentLayout;
     38
    3839class RenderThemeIOS final : public RenderTheme {
    3940public:
    … …  
    111112#endif
    112113
     114#if ENABLE(ATTACHMENT_ELEMENT)
     115    LayoutSize attachmentIntrinsicSize(const RenderAttachment&) const override;
     116    int attachmentBaseline(const RenderAttachment&) const override;
     117    bool paintAttachment(const RenderObject&, const PaintInfo&, const IntRect&) override;
     118#endif
     119
    113120private:
    114121    RenderThemeIOS();
  • trunk/Source/WebCore/rendering/RenderThemeIOS.mm

    r197563 r197600  
    2828#if PLATFORM(IOS)
    2929
     30#import "BitmapImage.h"
    3031#import "CSSPrimitiveValue.h"
    3132#import "CSSToLengthConversionData.h"
    … …  
    3435#import "DateComponents.h"
    3536#import "Document.h"
     37#import "File.h"
    3638#import "FloatRoundedRect.h"
    3739#import "FontCache.h"
    3840#import "FontCascade.h"
    3941#import "Frame.h"
     42#import "FrameSelection.h"
    4043#import "FrameView.h"
     44#import "GeometryUtilities.h"
    4145#import "Gradient.h"
    4246#import "GraphicsContext.h"
    4347#import "GraphicsContextCG.h"
     48#import "HTMLAttachmentElement.h"
    4449#import "HTMLInputElement.h"
    4550#import "HTMLNames.h"
    … …  
    5055#import "Page.h"
    5156#import "PaintInfo.h"
     57#import "PathUtilities.h"
    5258#import "PlatformLocale.h"
     59#import "RenderAttachment.h"
    5360#import "RenderObject.h"
    5461#import "RenderProgress.h"
    … …  
    5865#import "SoftLinking.h"
    5966#import "UIKitSPI.h"
     67#import "UTIUtilities.h"
    6068#import "UserAgentScripts.h"
    6169#import "UserAgentStyleSheets.h"
    … …  
    6775#import <wtf/StdLibExtras.h>
    6876
     77SOFT_LINK_FRAMEWORK(MobileCoreServices)
     78SOFT_LINK_CLASS(MobileCoreServices, LSDocumentProxy)
     79
    6980SOFT_LINK_FRAMEWORK(UIKit)
    7081SOFT_LINK_CLASS(UIKit, UIApplication)
    7182SOFT_LINK_CLASS(UIKit, UIColor)
     83SOFT_LINK_CLASS(UIKit, UIDocumentInteractionController)
     84SOFT_LINK_CLASS(UIKit, UIFont)
     85SOFT_LINK_CLASS(UIKit, UIImage)
    7286SOFT_LINK_CONSTANT(UIKit, UIContentSizeCategoryDidChangeNotification, CFStringRef)
     87SOFT_LINK_CONSTANT(UIKit, UIFontTextStyleFootnote, NSString *)
     88SOFT_LINK_CONSTANT(UIKit, UIFontTextStyleCaption1, NSString *)
    7389#define UIContentSizeCategoryDidChangeNotification getUIContentSizeCategoryDidChangeNotification()
    7490
    … …  
    8096
    8197namespace WebCore {
     98
     99using namespace HTMLNames;
    82100
    83101const float ControlBaseHeight = 20;
    … …  
    13221340}
    13231341
    1324 }
     1342#if ENABLE(ATTACHMENT_ELEMENT)
     1343
     1344const CGSize attachmentSize = { 160, 119 };
     1345
     1346const CGFloat attachmentBorderRadius = 16;
     1347static Color attachmentBorderColor() { return Color(204, 204, 204); }
     1348
     1349const CGFloat attachmentProgressSize = 36;
     1350const CGFloat attachmentIconSize = 48;
     1351
     1352const CGFloat attachmentItemMargin = 8;
     1353
     1354const CGFloat attachmentTitleMaximumWidth = 140;
     1355const CFIndex attachmentTitleMaximumLineCount = 2;
     1356
     1357// FIXME: Should be emphasized.
     1358static UIFont *attachmentActionFont() { return [getUIFontClass() preferredFontForTextStyle:getUIFontTextStyleFootnote()]; }
     1359static UIColor *attachmentActionColor() { return [getUIColorClass() systemBlueColor]; }
     1360
     1361static UIFont *attachmentTitleFont() { return [getUIFontClass() preferredFontForTextStyle:getUIFontTextStyleCaption1()]; }
     1362static UIColor *attachmentTitleColor() { return [getUIColorClass() systemGrayColor]; }
     1363
     1364static UIFont *attachmentSubtitleFont() { return [getUIFontClass() preferredFontForTextStyle:getUIFontTextStyleCaption1()]; }
     1365static UIColor *attachmentSubtitleColor() { return [getUIColorClass() systemGrayColor]; }
     1366
     1367struct AttachmentInfo {
     1368    explicit AttachmentInfo(const RenderAttachment&);
     1369
     1370    FloatRect iconRect;
     1371    FloatRect attachmentRect;
     1372    FloatRect progressRect;
     1373
     1374    BOOL hasProgress { NO };
     1375    float progress;
     1376
     1377    RetainPtr<UIImage> icon;
     1378
     1379    int baseline { 0 };
     1380
     1381    struct LabelLine {
     1382        FloatRect rect;
     1383        RetainPtr<CTLineRef> line;
     1384    };
     1385    Vector<LabelLine> lines;
     1386
     1387    CGFloat contentYOrigin { 0 };
     1388
     1389private:
     1390    void buildTitleLines(const RenderAttachment&);
     1391    void buildSingleLine(const String&, UIFont *, UIColor *);
     1392
     1393    void addLine(CTLineRef);
     1394};
     1395
     1396void AttachmentInfo::addLine(CTLineRef line)
     1397{
     1398    CGRect lineBounds = CTLineGetBoundsWithOptions(line, kCTLineBoundsExcludeTypographicLeading);
     1399    CGFloat trailingWhitespaceWidth = CTLineGetTrailingWhitespaceWidth(line);
     1400    CGFloat lineWidthIgnoringTrailingWhitespace = lineBounds.size.width - trailingWhitespaceWidth;
     1401    CGFloat lineHeight = CGCeiling(lineBounds.size.height + lineBounds.origin.y);
     1402
     1403    CGFloat xOffset = (attachmentRect.width() / 2) - (lineWidthIgnoringTrailingWhitespace / 2);
     1404    LabelLine labelLine;
     1405    labelLine.line = line;
     1406    labelLine.rect = FloatRect(xOffset, 0, lineWidthIgnoringTrailingWhitespace, lineHeight);
     1407
     1408    lines.append(labelLine);
     1409}
     1410
     1411void AttachmentInfo::buildTitleLines(const RenderAttachment& attachment)
     1412{
     1413    RetainPtr<UIFont> font = attachmentTitleFont();
     1414
     1415    String title = attachment.attachmentElement().attachmentTitle();
     1416    if (title.isEmpty())
     1417        return;
     1418
     1419    NSDictionary *textAttributes = @{
     1420        (id)kCTFontAttributeName: font.get(),
     1421        (id)kCTForegroundColorAttributeName: attachmentTitleColor()
     1422    };
     1423    RetainPtr<NSAttributedString> attributedTitle = adoptNS([[NSAttributedString alloc] initWithString:title attributes:textAttributes]);
     1424    RetainPtr<CTFramesetterRef> titleFramesetter = adoptCF(CTFramesetterCreateWithAttributedString((CFAttributedStringRef)attributedTitle.get()));
     1425
     1426    CFRange fitRange;
     1427    CGSize titleTextSize = CTFramesetterSuggestFrameSizeWithConstraints(titleFramesetter.get(), CFRangeMake(0, 0), nullptr, CGSizeMake(attachmentTitleMaximumWidth, CGFLOAT_MAX), &fitRange);
     1428
     1429    RetainPtr<CGPathRef> titlePath = adoptCF(CGPathCreateWithRect(CGRectMake(0, 0, titleTextSize.width, titleTextSize.height), nullptr));
     1430    RetainPtr<CTFrameRef> titleFrame = adoptCF(CTFramesetterCreateFrame(titleFramesetter.get(), fitRange, titlePath.get(), nullptr));
     1431
     1432    CFArrayRef ctLines = CTFrameGetLines(titleFrame.get());
     1433    CFIndex lineCount = CFArrayGetCount(ctLines);
     1434    if (!lineCount)
     1435        return;
     1436
     1437    // Lay out and record the first (attachmentTitleMaximumLineCount - 1) lines.
     1438    CFIndex lineIndex = 0;
     1439    for (; lineIndex < std::min(attachmentTitleMaximumLineCount - 1, lineCount); ++lineIndex) {
     1440        CTLineRef line = (CTLineRef)CFArrayGetValueAtIndex(ctLines, lineIndex);
     1441        addLine(line);
     1442    }
     1443
     1444    if (lineIndex == lineCount)
     1445        return;
     1446
     1447    // We had text that didn't fit in the first (attachmentTitleMaximumLineCount - 1) lines.
     1448    // Combine it into one last line, and center-truncate it.
     1449    CTLineRef firstRemainingLine = (CTLineRef)CFArrayGetValueAtIndex(ctLines, lineIndex);
     1450    CFIndex remainingRangeStart = CTLineGetStringRange(firstRemainingLine).location;
     1451    NSRange remainingRange = NSMakeRange(remainingRangeStart, [attributedTitle length] - remainingRangeStart);
     1452    NSAttributedString *remainingString = [attributedTitle attributedSubstringFromRange:remainingRange];
     1453    RetainPtr<CTLineRef> remainingLine = adoptCF(CTLineCreateWithAttributedString((CFAttributedStringRef)remainingString));
     1454    RetainPtr<NSAttributedString> ellipsisString = adoptNS([[NSAttributedString alloc] initWithString:@"\u2026" attributes:textAttributes]);
     1455    RetainPtr<CTLineRef> ellipsisLine = adoptCF(CTLineCreateWithAttributedString((CFAttributedStringRef)ellipsisString.get()));
     1456    RetainPtr<CTLineRef> truncatedLine = adoptCF(CTLineCreateTruncatedLine(remainingLine.get(), attachmentTitleMaximumWidth, kCTLineTruncationMiddle, ellipsisLine.get()));
     1457
     1458    if (!truncatedLine)
     1459        truncatedLine = remainingLine;
     1460
     1461    addLine(truncatedLine.get());
     1462}
     1463
     1464void AttachmentInfo::buildSingleLine(const String& text, UIFont *font, UIColor *color)
     1465{
     1466    if (text.isEmpty())
     1467        return;
     1468
     1469    NSDictionary *textAttributes = @{
     1470        (id)kCTFontAttributeName: font,
     1471        (id)kCTForegroundColorAttributeName: color
     1472    };
     1473    RetainPtr<NSAttributedString> attributedText = adoptNS([[NSAttributedString alloc] initWithString:text attributes:textAttributes]);
     1474
     1475    addLine(adoptCF(CTLineCreateWithAttributedString((CFAttributedStringRef)attributedText.get())).get());
     1476}
     1477
     1478static BOOL getAttachmentProgress(const RenderAttachment& attachment, float& progress)
     1479{
     1480    String progressString = attachment.attachmentElement().fastGetAttribute(progressAttr);
     1481    if (progressString.isEmpty())
     1482        return NO;
     1483    bool validProgress;
     1484    progress = progressString.toFloat(&validProgress);
     1485    return validProgress;
     1486}
     1487
     1488static RetainPtr<UIImage> iconForAttachment(const RenderAttachment& attachment, FloatSize& size)
     1489{
     1490    String MIMEType = attachment.attachmentElement().attachmentType();
     1491
     1492    String fileName;
     1493    if (File* file = attachment.attachmentElement().file())
     1494        fileName = file->name();
     1495
     1496    if (fileName.isEmpty())
     1497        fileName = attachment.attachmentElement().attachmentTitle();
     1498
     1499    RetainPtr<UIImage> result;
     1500
     1501    RetainPtr<UIDocumentInteractionController> documentInteractionController = adoptNS([[getUIDocumentInteractionControllerClass() alloc] init]);
     1502    [documentInteractionController setName:fileName];
     1503    [documentInteractionController setUTI:static_cast<NSString *>(mimeTypeFromUTITree(MIMEType.createCFString().get()).get())];
     1504
     1505    NSArray *icons = [documentInteractionController icons];
     1506    if (!icons.count)
     1507        return nil;
     1508
     1509    result = icons.lastObject;
     1510
     1511    BOOL useHeightForClosestMatch = [result size].height > [result size].width;
     1512    CGFloat bestMatchRatio = -1;
     1513
     1514    for (UIImage *icon in icons) {
     1515        CGFloat iconSize = useHeightForClosestMatch ? icon.size.height : icon.size.width;
     1516
     1517        CGFloat matchRatio = (attachmentIconSize / iconSize) - 1.0f;
     1518        if (matchRatio < 0.3f) {
     1519            matchRatio = CGFAbs(matchRatio);
     1520            if ((bestMatchRatio == -1) || (matchRatio < bestMatchRatio)) {
     1521                result = icon;
     1522                bestMatchRatio = matchRatio;
     1523            }
     1524        }
     1525    }
     1526
     1527    CGFloat iconAspect = [result size].width / [result size].height;
     1528    size = largestRectWithAspectRatioInsideRect(iconAspect, FloatRect(0, 0, attachmentIconSize, attachmentIconSize)).size();
     1529
     1530    return result;
     1531}
     1532
     1533AttachmentInfo::AttachmentInfo(const RenderAttachment& attachment)
     1534{
     1535    attachmentRect = FloatRect(0, 0, attachmentSize.width, attachmentSize.height);
     1536
     1537    hasProgress = getAttachmentProgress(attachment, progress);
     1538
     1539    String action = attachment.attachmentElement().fastGetAttribute(actionAttr);
     1540    String subtitle = attachment.attachmentElement().fastGetAttribute(subtitleAttr);
     1541
     1542    CGFloat yOffset = 0;
     1543
     1544    if (hasProgress) {
     1545        progressRect = FloatRect((attachmentRect.width() / 2) - (attachmentProgressSize / 2), 0, attachmentProgressSize, attachmentProgressSize);
     1546        yOffset += attachmentProgressSize + attachmentItemMargin;
     1547    }
     1548
     1549    if (action.isEmpty() && !hasProgress) {
     1550        FloatSize iconSize;
     1551        icon = iconForAttachment(attachment, iconSize);
     1552        if (icon) {
     1553            iconRect = FloatRect(FloatPoint((attachmentRect.width() / 2) - (iconSize.width() / 2), 0), iconSize);
     1554            yOffset += iconRect.height() + attachmentItemMargin;
     1555        }
     1556    } else
     1557        buildSingleLine(action, attachmentActionFont(), attachmentActionColor());
     1558
     1559    buildTitleLines(attachment);
     1560    buildSingleLine(subtitle, attachmentSubtitleFont(), attachmentSubtitleColor());
     1561
     1562    if (!lines.isEmpty()) {
     1563        for (auto& line : lines) {
     1564            line.rect.setY(yOffset);
     1565            yOffset += line.rect.height() + attachmentItemMargin;
     1566        }
     1567    }
     1568
     1569    contentYOrigin = (attachmentRect.height() / 2) - (yOffset / 2);
     1570}
     1571
     1572LayoutSize RenderThemeIOS::attachmentIntrinsicSize(const RenderAttachment&) const
     1573{
     1574    return LayoutSize(FloatSize(attachmentSize));
     1575}
     1576
     1577int RenderThemeIOS::attachmentBaseline(const RenderAttachment& attachment) const
     1578{
     1579    AttachmentInfo info(attachment);
     1580    return info.baseline;
     1581}
     1582
     1583static void paintAttachmentIcon(GraphicsContext& context, AttachmentInfo& info)
     1584{
     1585    if (!info.icon)
     1586        return;
     1587
     1588    RefPtr<Image> iconImage = BitmapImage::create([info.icon CGImage]);
     1589    if (!iconImage)
     1590        return;
     1591
     1592    context.drawImage(*iconImage, info.iconRect);
     1593}
     1594
     1595
     1596static void paintAttachmentText(GraphicsContext& context, AttachmentInfo& info)
     1597{
     1598    for (const auto& line : info.lines) {
     1599        GraphicsContextStateSaver saver(context);
     1600
     1601        context.translate(toFloatSize(line.rect.minXMaxYCorner()));
     1602        context.scale(FloatSize(1, -1));
     1603
     1604        CGContextSetTextMatrix(context.platformContext(), CGAffineTransformIdentity);
     1605        CTLineDraw(line.line.get(), context.platformContext());
     1606    }
     1607}
     1608
     1609static void paintAttachmentProgress(GraphicsContext& context, AttachmentInfo& info)
     1610{
     1611    GraphicsContextStateSaver saver(context);
     1612
     1613    // FIXME: Implement progress indicator.
     1614    context.fillRect(info.progressRect, Color(0, 255, 0));
     1615}
     1616
     1617static void paintAttachmentBorder(GraphicsContext& context, AttachmentInfo& info)
     1618{
     1619    Path borderPath;
     1620    borderPath.addRoundedRect(info.attachmentRect, FloatSize(attachmentBorderRadius, attachmentBorderRadius));
     1621    context.setStrokeColor(attachmentBorderColor());
     1622    context.setStrokeThickness(1);
     1623    context.strokePath(borderPath);
     1624}
     1625
     1626bool RenderThemeIOS::paintAttachment(const RenderObject& renderer, const PaintInfo& paintInfo, const IntRect& paintRect)
     1627{
     1628    if (!is<RenderAttachment>(renderer))
     1629        return false;
     1630
     1631    const RenderAttachment& attachment = downcast<RenderAttachment>(renderer);
     1632
     1633    AttachmentInfo info(attachment);
     1634
     1635    GraphicsContext& context = paintInfo.context();
     1636    GraphicsContextStateSaver saver(context);
     1637
     1638    context.translate(toFloatSize(paintRect.location()));
     1639
     1640    paintAttachmentBorder(context, info);
     1641
     1642    context.translate(FloatSize(0, info.contentYOrigin));
     1643
     1644    if (info.hasProgress)
     1645        paintAttachmentProgress(context, info);
     1646    else if (info.icon)
     1647        paintAttachmentIcon(context, info);
     1648
     1649    paintAttachmentText(context, info);
     1650
     1651    return true;
     1652}
     1653
     1654#endif // ENABLE(ATTACHMENT_ELEMENT)
     1655
     1656} // namespace WebCore
    13251657
    13261658#endif //PLATFORM(IOS)
Note: See TracChangeset for help on using the changeset viewer.