Changeset 275128 in webkit


Ignore:
Timestamp:
Mar 26, 2021 8:27:27 PM (16 months ago)
Author:
Patrick Angle
Message:

Web Inspector: Grid layout labels can be drawn outside the viewport
https://bugs.webkit.org/show_bug.cgi?id=221972

Reviewed by BJ Burg.

Source/WebCore:

Added logic for a best-effort attempt to make sure that layout labels are drawn within the document's bounds, or
at least within the grid itself. Labels are measured and adjusted so that if they would be drawn outside the
document's bounds, they will be pulled inside the grid. This does not guarantee that all labels will be visible
all the time. It is still possible an entire side of a grid will be outside the document's bounds, and this does
not attempt to correct for this case, as the desired anchor points for labels will be outside of the visible
area of the document.

  • inspector/InspectorOverlay.cpp:

(WebCore::InspectorOverlay::fontForLayoutLabel):

  • Added helper that creates the FontCascade for layout labels, which is done in a few different places.

(WebCore::InspectorOverlay::backgroundPathForLayoutLabel):

  • Added helper to create the Path for the background of layout labels, which is now used in WebKit::WKInspectorHighlightView.

(WebCore::expectedSizeForLayoutLabel):

  • Gets the expected size of the label based on the text and arrow direction, and does so without needing to

create the entire label background's path.
(WebCore::InspectorOverlay::drawLayoutLabel):

  • Support new LabelArrowEdgePosition property

(WebCore::InspectorOverlay::drawGridOverlay):
(WebCore::buildLabel):
(WebCore::InspectorOverlay::buildGridOverlay):

  • inspector/InspectorOverlay.h:

(WebCore::InspectorOverlay::Highlight::GridHighlightOverlay::Label::encode const):
(WebCore::InspectorOverlay::Highlight::GridHighlightOverlay::Label::decode):

Source/WebKit:

Add support for the new WebCore::InspectorOverlay::LabelArrowEdgePosition property to grid overlays on iOS.

  • UIProcess/Inspector/ios/WKInspectorHighlightView.mm:

(createLayoutLabelLayer):

  • Support the new WebCore::InspectorOverlay::LabelArrowEdgePosition.
  • Use new helpers in WebCore::InspectorOverlay to reduce code duplication.

(-[WKInspectorHighlightView _createGridOverlayLayer:scale:]):

Location:
trunk/Source
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r275126 r275128  
     12021-03-26  Patrick Angle  <pangle@apple.com>
     2
     3        Web Inspector: Grid layout labels can be drawn outside the viewport
     4        https://bugs.webkit.org/show_bug.cgi?id=221972
     5
     6        Reviewed by BJ Burg.
     7
     8        Added logic for a best-effort attempt to make sure that layout labels are drawn within the document's bounds, or
     9        at least within the grid itself. Labels are measured and adjusted so that if they would be drawn outside the
     10        document's bounds, they will be pulled inside the grid. This does not guarantee that all labels will be visible
     11        all the time. It is still possible an entire side of a grid will be outside the document's bounds, and this does
     12        not attempt to correct for this case, as the desired anchor points for labels will be outside of the visible
     13        area of the document.
     14
     15        * inspector/InspectorOverlay.cpp:
     16        (WebCore::InspectorOverlay::fontForLayoutLabel):
     17        - Added helper that creates the FontCascade for layout labels, which is done in a few different places.
     18        (WebCore::InspectorOverlay::backgroundPathForLayoutLabel):
     19        - Added helper to create the Path for the background of layout labels, which is now used in `WebKit::WKInspectorHighlightView`.
     20        (WebCore::expectedSizeForLayoutLabel):
     21        - Gets the expected size of the label based on the text and arrow direction, and does so without needing to
     22        create the entire label background's path.
     23        (WebCore::InspectorOverlay::drawLayoutLabel):
     24        - Support new `LabelArrowEdgePosition` property
     25        (WebCore::InspectorOverlay::drawGridOverlay):
     26        (WebCore::buildLabel):
     27        (WebCore::InspectorOverlay::buildGridOverlay):
     28        * inspector/InspectorOverlay.h:
     29        (WebCore::InspectorOverlay::Highlight::GridHighlightOverlay::Label::encode const):
     30        (WebCore::InspectorOverlay::Highlight::GridHighlightOverlay::Label::decode):
     31
    1322021-03-26  Zalan Bujtas  <zalan@apple.com>
    233
  • trunk/Source/WebCore/inspector/InspectorOverlay.cpp

    r274822 r275128  
    8585static constexpr float rulerSubStepLength = 5;
    8686
     87static constexpr float layoutLabelPadding = 3;
     88static constexpr float layoutLabelArrowSize = 4;
     89
    8790static constexpr UChar bullet = 0x2022;
    8891static constexpr UChar ellipsis = 0x2026;
     
    12001203}
    12011204
    1202 void InspectorOverlay::drawLayoutLabel(GraphicsContext& context, String label, FloatPoint point, InspectorOverlay::LabelArrowDirection direction, Color backgroundColor, float maximumWidth)
    1203 {
    1204     GraphicsContextStateSaver saver(context);
    1205    
    1206     context.translate(point);
    1207    
     1205FontCascade InspectorOverlay::fontForLayoutLabel()
     1206{
    12081207    FontCascadeDescription fontDescription;
    12091208    fontDescription.setFamilies({ "system-ui" });
     
    12131212    FontCascade font(WTFMove(fontDescription), 0, 0);
    12141213    font.update(nullptr);
    1215 
    1216     constexpr auto padding = 4;
    1217     constexpr auto arrowSize = 4;
     1214    return font;
     1215}
     1216
     1217Path InspectorOverlay::backgroundPathForLayoutLabel(float width, float height, InspectorOverlay::LabelArrowDirection arrowDirection, InspectorOverlay::LabelArrowEdgePosition arrowEdgePosition, float arrowSize)
     1218{
     1219    Path path;
     1220    FloatSize offsetForArrowEdgePosition;
     1221
     1222    switch (arrowDirection) {
     1223    case InspectorOverlay::LabelArrowDirection::Down:
     1224        path.moveTo({ -(width / 2), -height - arrowSize});
     1225        path.addLineTo({ -(width / 2), -arrowSize });
     1226
     1227        switch (arrowEdgePosition) {
     1228        case InspectorOverlay::LabelArrowEdgePosition::Leading:
     1229            path.addLineTo({ -(width / 2), 0 });
     1230            path.addLineTo({ -(width / 2) + arrowSize, -arrowSize });
     1231            offsetForArrowEdgePosition = { (width / 2), 0 };
     1232            break;
     1233        case InspectorOverlay::LabelArrowEdgePosition::Middle:
     1234            path.addLineTo({ -arrowSize, -arrowSize });
     1235            path.addLineTo({ 0, 0 });
     1236            path.addLineTo({ arrowSize, -arrowSize });
     1237            break;
     1238        case InspectorOverlay::LabelArrowEdgePosition::Trailing:
     1239            path.addLineTo({ (width / 2) - arrowSize, -arrowSize });
     1240            path.addLineTo({ (width / 2), 0 });
     1241            offsetForArrowEdgePosition = { -(width / 2), 0 };
     1242            break;
     1243        case InspectorOverlay::LabelArrowEdgePosition::None:
     1244            break;
     1245        }
     1246
     1247        path.addLineTo({ (width / 2), -arrowSize });
     1248        path.addLineTo({ (width / 2), -height - arrowSize });
     1249        break;
     1250    case InspectorOverlay::LabelArrowDirection::Up:
     1251        path.moveTo({ -(width / 2), height + arrowSize });
     1252        path.addLineTo({ -(width / 2), arrowSize });
     1253
     1254        switch (arrowEdgePosition) {
     1255        case InspectorOverlay::LabelArrowEdgePosition::Leading:
     1256            path.addLineTo({ -(width / 2), 0 });
     1257            path.addLineTo({ -(width / 2) + arrowSize, arrowSize });
     1258            offsetForArrowEdgePosition = { (width / 2), 0 };
     1259            break;
     1260        case InspectorOverlay::LabelArrowEdgePosition::Middle:
     1261            path.addLineTo({ -arrowSize, arrowSize });
     1262            path.addLineTo({ 0, 0 });
     1263            path.addLineTo({ arrowSize, arrowSize });
     1264            break;
     1265        case InspectorOverlay::LabelArrowEdgePosition::Trailing:
     1266            path.addLineTo({ (width / 2) - arrowSize, arrowSize });
     1267            path.addLineTo({ (width / 2), 0 });
     1268            offsetForArrowEdgePosition = { -(width / 2), 0 };
     1269            break;
     1270        case InspectorOverlay::LabelArrowEdgePosition::None:
     1271            break;
     1272        }
     1273
     1274        path.addLineTo({ (width / 2), arrowSize });
     1275        path.addLineTo({ (width / 2), height + arrowSize });
     1276        break;
     1277    case InspectorOverlay::LabelArrowDirection::Right:
     1278        path.moveTo({ -width - arrowSize, (height / 2) });
     1279        path.addLineTo({ -arrowSize, (height / 2) });
     1280
     1281        switch (arrowEdgePosition) {
     1282        case InspectorOverlay::LabelArrowEdgePosition::Leading:
     1283            path.addLineTo({ -arrowSize, -(height / 2) + arrowSize });
     1284            path.addLineTo({ 0, -(height / 2) });
     1285            offsetForArrowEdgePosition = { 0, (height / 2) };
     1286            break;
     1287        case InspectorOverlay::LabelArrowEdgePosition::Middle:
     1288            path.addLineTo({ -arrowSize, arrowSize });
     1289            path.addLineTo({ 0, 0 });
     1290            path.addLineTo({ -arrowSize, -arrowSize });
     1291            break;
     1292        case InspectorOverlay::LabelArrowEdgePosition::Trailing:
     1293            path.addLineTo({ 0, (height / 2) });
     1294            path.addLineTo({ -arrowSize, (height / 2) - arrowSize });
     1295            offsetForArrowEdgePosition = { 0, -(height / 2) };
     1296            break;
     1297        case InspectorOverlay::LabelArrowEdgePosition::None:
     1298            break;
     1299        }
     1300
     1301        path.addLineTo({ -arrowSize, -(height / 2) });
     1302        path.addLineTo({ -width - arrowSize, -(height / 2) });
     1303        break;
     1304    case InspectorOverlay::LabelArrowDirection::Left:
     1305        path.moveTo({ width + arrowSize, (height / 2) });
     1306        path.addLineTo({ arrowSize, (height / 2) });
     1307
     1308        switch (arrowEdgePosition) {
     1309        case InspectorOverlay::LabelArrowEdgePosition::Leading:
     1310            path.addLineTo({ arrowSize, -(height / 2) + arrowSize });
     1311            path.addLineTo({ 0, -(height / 2) });
     1312            offsetForArrowEdgePosition = { 0, (height / 2) };
     1313            break;
     1314        case InspectorOverlay::LabelArrowEdgePosition::Middle:
     1315            path.addLineTo({ arrowSize, arrowSize });
     1316            path.addLineTo({ 0, 0 });
     1317            path.addLineTo({ arrowSize, -arrowSize });
     1318            break;
     1319        case InspectorOverlay::LabelArrowEdgePosition::Trailing:
     1320            path.addLineTo({ 0, (height / 2) });
     1321            path.addLineTo({ arrowSize, (height / 2) - arrowSize });
     1322            offsetForArrowEdgePosition = { 0, -(height / 2) };
     1323            break;
     1324        case InspectorOverlay::LabelArrowEdgePosition::None:
     1325            break;
     1326        }
     1327
     1328        path.addLineTo({ arrowSize, -(height / 2) });
     1329        path.addLineTo({ width + arrowSize, -(height / 2) });
     1330        break;
     1331    case InspectorOverlay::LabelArrowDirection::None:
     1332        path.addLineTo({ 0, height });
     1333        path.addLineTo({ width, height });
     1334        path.addLineTo({ width, 0 });
     1335        break;
     1336    }
     1337
     1338    path.closeSubpath();
     1339    path.translate(offsetForArrowEdgePosition);
     1340
     1341    return path;
     1342}
     1343
     1344static FloatSize expectedSizeForLayoutLabel(String label, InspectorOverlay::LabelArrowDirection direction, float maximumWidth = 0)
     1345{
     1346    auto font = InspectorOverlay::fontForLayoutLabel();
     1347
     1348    float textHeight = font.fontMetrics().floatHeight();
     1349    float textWidth = font.width(TextRun(label));
     1350    if (maximumWidth && textWidth + (layoutLabelPadding * 2) > maximumWidth)
     1351        textWidth = maximumWidth;
     1352
     1353    switch (direction) {
     1354    case InspectorOverlay::LabelArrowDirection::Down:
     1355    case InspectorOverlay::LabelArrowDirection::Up:
     1356        return { textWidth + (layoutLabelPadding * 2), textHeight + (layoutLabelPadding * 2) + layoutLabelArrowSize };
     1357    case InspectorOverlay::LabelArrowDirection::Right:
     1358    case InspectorOverlay::LabelArrowDirection::Left:
     1359        return { textWidth + (layoutLabelPadding * 2) + layoutLabelArrowSize, textHeight + (layoutLabelPadding * 2) };
     1360    case InspectorOverlay::LabelArrowDirection::None:
     1361        return { textWidth + (layoutLabelPadding * 2), textHeight + (layoutLabelPadding * 2) };
     1362    }
     1363}
     1364
     1365void InspectorOverlay::drawLayoutLabel(GraphicsContext& context, String label, FloatPoint point, InspectorOverlay::LabelArrowDirection arrowDirection, InspectorOverlay::LabelArrowEdgePosition arrowEdgePosition, Color backgroundColor, float maximumWidth)
     1366{
     1367    ASSERT(arrowEdgePosition != LabelArrowEdgePosition::None || arrowDirection == LabelArrowDirection::None);
     1368
     1369    GraphicsContextStateSaver saver(context);
     1370   
     1371    context.translate(point);
     1372
     1373    auto font = fontForLayoutLabel();
    12181374    float textHeight = font.fontMetrics().floatHeight();
    12191375    float textDescent = font.fontMetrics().floatDescent();
    12201376   
    12211377    float textWidth = font.width(TextRun(label));
    1222     if (maximumWidth && textWidth + (padding * 2) > maximumWidth) {
     1378    if (maximumWidth && textWidth + (layoutLabelPadding * 2) > maximumWidth) {
    12231379        label.append("..."_s);
    1224         while (textWidth + (padding * 2) > maximumWidth && label.length() >= 4) {
     1380        while (textWidth + (layoutLabelPadding * 2) > maximumWidth && label.length() >= 4) {
    12251381            // Remove the fourth from last character (the character before the ellipsis) and remeasure.
    12261382            label.remove(label.length() - 4);
     
    12281384        }
    12291385    }
    1230    
    1231     Path labelPath;
     1386
    12321387    FloatPoint textPosition;
    1233    
    1234     switch (direction) {
     1388    switch (arrowDirection) {
    12351389    case InspectorOverlay::LabelArrowDirection::Down:
    1236         labelPath.moveTo({ -(textWidth / 2) - padding, -textHeight - (padding * 2) - arrowSize });
    1237         labelPath.addLineTo({ -(textWidth / 2) - padding, -arrowSize });
    1238         labelPath.addLineTo({ -arrowSize, -arrowSize });
    1239         labelPath.addLineTo({ 0, 0 });
    1240         labelPath.addLineTo({ arrowSize, -arrowSize });
    1241         labelPath.addLineTo({ (textWidth / 2) + padding, -arrowSize });
    1242         labelPath.addLineTo({ (textWidth / 2) + padding, -textHeight - (padding * 2) - arrowSize });
    1243         textPosition = FloatPoint(-(textWidth / 2), -textDescent - arrowSize - padding);
     1390        switch (arrowEdgePosition) {
     1391        case InspectorOverlay::LabelArrowEdgePosition::Leading:
     1392            textPosition = FloatPoint(layoutLabelPadding, -textDescent - layoutLabelArrowSize - layoutLabelPadding);
     1393            break;
     1394        case InspectorOverlay::LabelArrowEdgePosition::Middle:
     1395            textPosition = FloatPoint(-(textWidth / 2), -textDescent - layoutLabelArrowSize - layoutLabelPadding);
     1396            break;
     1397        case InspectorOverlay::LabelArrowEdgePosition::Trailing:
     1398            textPosition = FloatPoint(-(textWidth) - layoutLabelPadding, -textDescent - layoutLabelArrowSize - layoutLabelPadding);
     1399            break;
     1400        case InspectorOverlay::LabelArrowEdgePosition::None:
     1401            break;
     1402        }
    12441403        break;
    12451404    case InspectorOverlay::LabelArrowDirection::Up:
    1246         labelPath.moveTo({ -(textWidth / 2) - padding, textHeight + (padding * 2) + arrowSize });
    1247         labelPath.addLineTo({ -(textWidth / 2) - padding, arrowSize });
    1248         labelPath.addLineTo({ -arrowSize, arrowSize });
    1249         labelPath.addLineTo({ 0, 0 });
    1250         labelPath.addLineTo({ arrowSize, arrowSize });
    1251         labelPath.addLineTo({ (textWidth / 2) + padding, arrowSize });
    1252         labelPath.addLineTo({ (textWidth / 2) + padding, textHeight + (padding * 2) + arrowSize });
    1253         textPosition = FloatPoint(-(textWidth / 2), textHeight - textDescent + arrowSize + padding);
     1405        switch (arrowEdgePosition) {
     1406        case InspectorOverlay::LabelArrowEdgePosition::Leading:
     1407            textPosition = FloatPoint(layoutLabelPadding, textHeight - textDescent + layoutLabelArrowSize + layoutLabelPadding);
     1408            break;
     1409        case InspectorOverlay::LabelArrowEdgePosition::Middle:
     1410            textPosition = FloatPoint(-(textWidth / 2), textHeight - textDescent + layoutLabelArrowSize + layoutLabelPadding);
     1411            break;
     1412        case InspectorOverlay::LabelArrowEdgePosition::Trailing:
     1413            textPosition = FloatPoint(-(textWidth) - layoutLabelPadding, textHeight - textDescent + layoutLabelArrowSize + layoutLabelPadding);
     1414            break;
     1415        case InspectorOverlay::LabelArrowEdgePosition::None:
     1416            break;
     1417        }
    12541418        break;
    12551419    case InspectorOverlay::LabelArrowDirection::Right:
    1256         labelPath.moveTo({ -textWidth - (padding * 2) - arrowSize, (textHeight / 2) + padding });
    1257         labelPath.addLineTo({ -arrowSize, (textHeight / 2) + padding });
    1258         labelPath.addLineTo({ -arrowSize, arrowSize });
    1259         labelPath.addLineTo({ 0, 0 });
    1260         labelPath.addLineTo({ -arrowSize, -arrowSize });
    1261         labelPath.addLineTo({ -arrowSize, -(textHeight / 2) - padding });
    1262         labelPath.addLineTo({ -textWidth - (padding * 2) - arrowSize, -(textHeight / 2) - padding });
    1263         textPosition = FloatPoint(-textWidth - arrowSize - padding, (textHeight / 2) - textDescent);
     1420        switch (arrowEdgePosition) {
     1421        case InspectorOverlay::LabelArrowEdgePosition::Leading:
     1422            textPosition = FloatPoint(-textWidth - layoutLabelArrowSize - layoutLabelPadding, layoutLabelPadding + textHeight - textDescent);
     1423            break;
     1424        case InspectorOverlay::LabelArrowEdgePosition::Middle:
     1425            textPosition = FloatPoint(-textWidth - layoutLabelArrowSize - layoutLabelPadding, (textHeight / 2) - textDescent);
     1426            break;
     1427        case InspectorOverlay::LabelArrowEdgePosition::Trailing:
     1428            textPosition = FloatPoint(-textWidth - layoutLabelArrowSize - layoutLabelPadding, -layoutLabelPadding - textDescent);
     1429            break;
     1430        case InspectorOverlay::LabelArrowEdgePosition::None:
     1431            break;
     1432        }
    12641433        break;
    12651434    case InspectorOverlay::LabelArrowDirection::Left:
    1266         labelPath.moveTo({ textWidth + (padding * 2) + arrowSize, (textHeight / 2) + padding });
    1267         labelPath.addLineTo({ arrowSize, (textHeight / 2) + padding });
    1268         labelPath.addLineTo({ arrowSize, arrowSize });
    1269         labelPath.addLineTo({ 0, 0 });
    1270         labelPath.addLineTo({ arrowSize, -arrowSize });
    1271         labelPath.addLineTo({ arrowSize, -(textHeight / 2) - padding });
    1272         labelPath.addLineTo({ textWidth + (padding * 2) + arrowSize, -(textHeight / 2) - padding });
    1273         textPosition = FloatPoint(arrowSize + padding, (textHeight / 2) - textDescent);
     1435        switch (arrowEdgePosition) {
     1436        case InspectorOverlay::LabelArrowEdgePosition::Leading:
     1437            textPosition = FloatPoint(layoutLabelArrowSize + layoutLabelPadding, layoutLabelPadding + textHeight - textDescent);
     1438            break;
     1439        case InspectorOverlay::LabelArrowEdgePosition::Middle:
     1440            textPosition = FloatPoint(layoutLabelArrowSize + layoutLabelPadding, (textHeight / 2) - textDescent);
     1441            break;
     1442        case InspectorOverlay::LabelArrowEdgePosition::Trailing:
     1443            textPosition = FloatPoint(layoutLabelArrowSize + layoutLabelPadding, -layoutLabelPadding - textDescent);
     1444            break;
     1445        case InspectorOverlay::LabelArrowEdgePosition::None:
     1446            break;
     1447        }
    12741448        break;
    12751449    case InspectorOverlay::LabelArrowDirection::None:
    1276         labelPath.addLineTo({ 0, textHeight + (padding * 2) });
    1277         labelPath.addLineTo({ textWidth + (padding * 2), textHeight + (padding * 2) });
    1278         labelPath.addLineTo({ textWidth + (padding * 2), 0 });
    1279         textPosition = FloatPoint(padding, padding + textHeight - textDescent);
     1450        textPosition = FloatPoint(layoutLabelPadding, layoutLabelPadding + textHeight - textDescent);
    12801451        break;
    12811452    }
    1282    
    1283     labelPath.closeSubpath();
    1284    
     1453
     1454    Path labelPath = backgroundPathForLayoutLabel(textWidth + (layoutLabelPadding * 2), textHeight + (layoutLabelPadding * 2), arrowDirection, arrowEdgePosition, layoutLabelArrowSize);
     1455
    12851456    context.setFillColor(backgroundColor);
    12861457    context.fillPath(labelPath);
     
    13161487    context.setStrokeThickness(1);
    13171488    for (auto area : gridOverlay.areas)
    1318         drawLayoutLabel(context, area.name, area.quad.p1(), LabelArrowDirection::None, translucentLabelBackgroundColor, area.quad.boundingBox().width());
     1489        drawLayoutLabel(context, area.name, area.quad.p1(), LabelArrowDirection::None, LabelArrowEdgePosition::None, translucentLabelBackgroundColor, area.quad.boundingBox().width());
    13191490
    13201491    for (auto label : gridOverlay.labels)
    1321         drawLayoutLabel(context, label.text, label.location, label.arrowDirection, label.backgroundColor);
     1492        drawLayoutLabel(context, label.text, label.location, label.arrowDirection, label.arrowEdgePosition, label.backgroundColor);
    13221493}
    13231494
     
    14201591}
    14211592
    1422 static InspectorOverlay::Highlight::GridHighlightOverlay::Label buildLabel(String text, FloatPoint location, Color backgroundColor, InspectorOverlay::LabelArrowDirection arrowDirection)
     1593static InspectorOverlay::Highlight::GridHighlightOverlay::Label buildLabel(String text, FloatPoint location, Color backgroundColor, InspectorOverlay::LabelArrowDirection arrowDirection, InspectorOverlay::LabelArrowEdgePosition arrowEdgePosition)
    14231594{
    14241595    InspectorOverlay::Highlight::GridHighlightOverlay::Label label;
     
    14271598    label.backgroundColor = backgroundColor;
    14281599    label.arrowDirection = arrowDirection;
     1600    label.arrowEdgePosition = arrowEdgePosition;
    14291601    return label;
    14301602}
     
    14551627        return { };
    14561628    FloatRect viewportBounds = { { 0, 0 }, pageView->sizeForVisibleContent() };
     1629
     1630    auto scrollPosition = pageView->scrollPosition();
    14571631    if (offsetBoundsByScroll)
    1458         viewportBounds.setLocation(pageView->scrollPosition());
     1632        viewportBounds.setLocation(scrollPosition);
    14591633   
    14601634    auto& renderGrid = *downcast<RenderGrid>(renderer);
     
    15051679        }
    15061680       
    1507         FloatPoint gapLabelPosition = columnStartLine.start();
     1681        FloatLine gapLabelLine = columnStartLine;
    15081682        if (i) {
    15091683            gridHighlightOverlay.gaps.append({ previousColumnEndLine.start(), columnStartLine.start(), columnStartLine.end(), previousColumnEndLine.end() });
    15101684            FloatLine lineBetweenColumnTops = { columnStartLine.start(), previousColumnEndLine.start() };
    1511             gapLabelPosition = lineBetweenColumnTops.pointAtRelativeDistance(0.5);
     1685            FloatLine lineBetweenColumnBottoms = { columnStartLine.end(), previousColumnEndLine.end() };
     1686            gapLabelLine = { lineBetweenColumnTops.pointAtRelativeDistance(0.5), lineBetweenColumnTops.pointAtRelativeDistance(0.5) };
    15121687        }
    15131688
     
    15401715               
    15411716                FloatLine trackTopLine = { columnStartLine.start(), columnEndLine.start() };
    1542                 gridHighlightOverlay.labels.append(buildLabel(trackSizeLabel, trackTopLine.pointAtRelativeDistance(0.5), translucentLabelBackgroundColor, LabelArrowDirection::Up));
     1717                gridHighlightOverlay.labels.append(buildLabel(trackSizeLabel, trackTopLine.pointAtRelativeDistance(0.5), translucentLabelBackgroundColor, LabelArrowDirection::Up, LabelArrowEdgePosition::Middle));
    15431718            }
    15441719        } else
     
    15551730            }
    15561731        }
    1557         // FIXME: <webkit.org/b/221972> Layout labels can be drawn outside the viewport, and a best effort should be made to keep them in the viewport while the grid is in the viewport.
    1558         if (!lineLabel.isEmpty())
    1559             gridHighlightOverlay.labels.append(buildLabel(lineLabel.toString(), gapLabelPosition, Color::white, LabelArrowDirection::Down));
     1732
     1733        if (!lineLabel.isEmpty()) {
     1734            auto text = lineLabel.toString();
     1735            auto arrowDirection = LabelArrowDirection::Down;
     1736            auto arrowEdgePosition = LabelArrowEdgePosition::Middle;
     1737
     1738            if (!i)
     1739                arrowEdgePosition = LabelArrowEdgePosition::Leading;
     1740            else if (i == columnPositions.size() - 1)
     1741                arrowEdgePosition = LabelArrowEdgePosition::Trailing;
     1742
     1743            auto expectedLabelSize = expectedSizeForLayoutLabel(text, arrowDirection);
     1744            auto gapLabelPosition = gapLabelLine.start();
     1745
     1746            // The area under the window's toolbar is drawable, but not meaningfully visible, so we must account for that space.
     1747            auto topEdgeInset = pageView->topContentInset(ScrollView::TopContentInsetType::WebCoreOrPlatformContentInset);
     1748            if (gapLabelLine.start().y() - expectedLabelSize.height() - topEdgeInset + scrollPosition.y() - viewportBounds.y() < 0) {
     1749                arrowDirection = LabelArrowDirection::Up;
     1750
     1751                // Special case for the first column to make sure the label will be out of the way of the first row's label.
     1752                // The label heights will be the same, as they use the same font, so moving down by this label's size will
     1753                // create enough space for this special circumstance.
     1754                if (!i)
     1755                    gapLabelPosition = gapLabelLine.pointAtAbsoluteDistance(expectedLabelSize.height());
     1756            }
     1757
     1758            gridHighlightOverlay.labels.append(buildLabel(text, gapLabelPosition, Color::white, arrowDirection, arrowEdgePosition));
     1759        }
    15601760    }
    15611761
     
    16081808                }
    16091809                FloatLine trackLeftLine = { rowStartLine.start(), rowEndLine.start() };
    1610                 gridHighlightOverlay.labels.append(buildLabel(trackSizeLabel, trackLeftLine.pointAtRelativeDistance(0.5), translucentLabelBackgroundColor, LabelArrowDirection::Left));
     1810                gridHighlightOverlay.labels.append(buildLabel(trackSizeLabel, trackLeftLine.pointAtRelativeDistance(0.5), translucentLabelBackgroundColor, LabelArrowDirection::Left, LabelArrowEdgePosition::Middle));
    16111811            }
    16121812        } else
     
    16231823            }
    16241824        }
    1625         // FIXME: <webkit.org/b/221972> Layout labels can be drawn outside the viewport, and a best effort should be made to keep them in the viewport while the grid is in the viewport.
    1626         if (!lineLabel.isEmpty())
    1627             gridHighlightOverlay.labels.append(buildLabel(lineLabel.toString(), gapLabelPosition, Color::white, LabelArrowDirection::Right));
     1825
     1826        if (!lineLabel.isEmpty()) {
     1827            auto text = lineLabel.toString();
     1828            auto arrowDirection = LabelArrowDirection::Right;
     1829            auto arrowEdgePosition = LabelArrowEdgePosition::Middle;
     1830
     1831            if (!i)
     1832                arrowEdgePosition = LabelArrowEdgePosition::Leading;
     1833            else if (i == rowPositions.size() - 1)
     1834                arrowEdgePosition = LabelArrowEdgePosition::Trailing;
     1835
     1836            auto expectedLabelSize = expectedSizeForLayoutLabel(text, arrowDirection);
     1837            if (gapLabelPosition.x() - expectedLabelSize.width() + scrollPosition.x() - viewportBounds.x() < 0)
     1838                arrowDirection = LabelArrowDirection::Left;
     1839
     1840            gridHighlightOverlay.labels.append(buildLabel(text, gapLabelPosition, Color::white, arrowDirection, arrowEdgePosition));
     1841        }
    16281842    }
    16291843
  • trunk/Source/WebCore/inspector/InspectorOverlay.h

    r274822 r275128  
    5353namespace WebCore {
    5454
     55class FontCascade;
    5556class FloatPoint;
    5657class GraphicsContext;
     
    7273        Left,
    7374        Right,
     75    };
     76
     77    enum class LabelArrowEdgePosition {
     78        None,
     79        Leading, // Positioned at the left/top side of edge.
     80        Middle, // Positioned at the center on the edge.
     81        Trailing, // Positioned at the right/bottom side of the edge.
    7482    };
    7583
     
    104112                Color backgroundColor;
    105113                LabelArrowDirection arrowDirection;
     114                LabelArrowEdgePosition arrowEdgePosition;
    106115
    107116#if PLATFORM(IOS_FAMILY)
     
    210219    void clearAllGridOverlays();
    211220
     221    WEBCORE_EXPORT static FontCascade fontForLayoutLabel();
     222    WEBCORE_EXPORT static Path backgroundPathForLayoutLabel(float, float, InspectorOverlay::LabelArrowDirection, InspectorOverlay::LabelArrowEdgePosition, float arrowSize);
    212223private:
    213224    using TimeRectPair = std::pair<MonotonicTime, FloatRect>;
     
    227238   
    228239    void drawLayoutHatching(GraphicsContext&, FloatQuad);
    229     void drawLayoutLabel(GraphicsContext&, String, FloatPoint, LabelArrowDirection, Color backgroundColor = Color::white, float maximumWidth = 0);
     240    void drawLayoutLabel(GraphicsContext&, String, FloatPoint, LabelArrowDirection, InspectorOverlay::LabelArrowEdgePosition, Color backgroundColor = Color::white, float maximumWidth = 0);
    230241
    231242    void drawGridOverlay(GraphicsContext&, const InspectorOverlay::Highlight::GridHighlightOverlay&);
     
    290301    encoder << backgroundColor;
    291302    encoder << static_cast<uint32_t>(arrowDirection);
     303    encoder << static_cast<uint32_t>(arrowEdgePosition);
    292304}
    293305
     
    307319    label.arrowDirection = (InspectorOverlay::LabelArrowDirection)arrowDirection;
    308320
     321    uint32_t arrowEdgePosition;
     322    if (!decoder.decode(arrowEdgePosition))
     323        return { };
     324    label.arrowEdgePosition = (InspectorOverlay::LabelArrowEdgePosition)arrowEdgePosition;
     325
    309326    return { label };
    310327}
  • trunk/Source/WebKit/ChangeLog

    r275120 r275128  
     12021-03-26  Patrick Angle  <pangle@apple.com>
     2
     3        Web Inspector: Grid layout labels can be drawn outside the viewport
     4        https://bugs.webkit.org/show_bug.cgi?id=221972
     5
     6        Reviewed by BJ Burg.
     7
     8        Add support for the new `WebCore::InspectorOverlay::LabelArrowEdgePosition` property to grid overlays on iOS.
     9
     10        * UIProcess/Inspector/ios/WKInspectorHighlightView.mm:
     11        (createLayoutLabelLayer):
     12        - Support the new `WebCore::InspectorOverlay::LabelArrowEdgePosition`.
     13        - Use new helpers in WebCore::InspectorOverlay to reduce code duplication.
     14        (-[WKInspectorHighlightView _createGridOverlayLayer:scale:]):
     15
    1162021-03-26  Wenson Hsieh  <wenson_hsieh@apple.com>
    217
  • trunk/Source/WebKit/UIProcess/Inspector/ios/WKInspectorHighlightView.mm

    r274822 r275128  
    319319}
    320320
    321 static CALayer * createLayoutLabelLayer(String label, WebCore::FloatPoint point, WebCore::InspectorOverlay::LabelArrowDirection direction, WebCore::Color backgroundColor, WebCore::Color strokeColor, double scale, float maximumWidth = 0)
    322 {
    323     WebCore::FontCascadeDescription fontDescription;
    324     fontDescription.setFamilies({ "system-ui" });
    325     fontDescription.setWeight(WebCore::FontSelectionValue(500));
    326     fontDescription.setComputedSize(12);
    327 
    328     WebCore::FontCascade font(WTFMove(fontDescription), 0, 0);
    329     font.update(nullptr);
     321static CALayer * createLayoutLabelLayer(String label, WebCore::FloatPoint point, WebCore::InspectorOverlay::LabelArrowDirection arrowDirection, WebCore::InspectorOverlay::LabelArrowEdgePosition arrowEdgePosition, WebCore::Color backgroundColor, WebCore::Color strokeColor, double scale, float maximumWidth = 0)
     322{
     323    auto font = WebCore::InspectorOverlay::fontForLayoutLabel();
    330324
    331325    constexpr auto padding = 4;
     
    343337    }
    344338
    345     auto labelPath = adoptCF(CGPathCreateMutable());
    346 
    347339    // Note: Implementation Difference - The textPosition is the center of text, unlike WebCore::InspectorOverlay, where the textPosition is leftmost point on the baseline of the text.
    348340    WebCore::FloatPoint textPosition;
    349 
    350     switch (direction) {
     341    switch (arrowDirection) {
    351342    case WebCore::InspectorOverlay::LabelArrowDirection::Down:
    352         CGPathMoveToPoint(labelPath.get(), 0, -(textWidth / 2) - padding, -textHeight - (padding * 2) - arrowSize);
    353         CGPathAddLineToPoint(labelPath.get(), 0, -(textWidth / 2) - padding, -arrowSize);
    354         CGPathAddLineToPoint(labelPath.get(), 0, -arrowSize, -arrowSize);
    355         CGPathAddLineToPoint(labelPath.get(), 0, 0, 0);
    356         CGPathAddLineToPoint(labelPath.get(), 0, arrowSize, -arrowSize);
    357         CGPathAddLineToPoint(labelPath.get(), 0, (textWidth / 2) + padding, -arrowSize);
    358         CGPathAddLineToPoint(labelPath.get(), 0, (textWidth / 2) + padding, -textHeight - (padding * 2) - arrowSize);
    359         textPosition = WebCore::FloatPoint(0, -(textHeight / 2) - arrowSize - padding);
     343        switch (arrowEdgePosition) {
     344        case WebCore::InspectorOverlay::LabelArrowEdgePosition::Leading:
     345            textPosition = WebCore::FloatPoint((textWidth / 2) + padding, -(textHeight / 2) - arrowSize - padding);
     346            break;
     347        case WebCore::InspectorOverlay::LabelArrowEdgePosition::Middle:
     348            textPosition = WebCore::FloatPoint(0, -(textHeight / 2) - arrowSize - padding);
     349            break;
     350        case WebCore::InspectorOverlay::LabelArrowEdgePosition::Trailing:
     351            textPosition = WebCore::FloatPoint(-(textWidth / 2) - padding, -(textHeight / 2) - arrowSize - padding);
     352            break;
     353        case WebCore::InspectorOverlay::LabelArrowEdgePosition::None:
     354            break;
     355        }
    360356        break;
    361357    case WebCore::InspectorOverlay::LabelArrowDirection::Up:
    362         CGPathMoveToPoint(labelPath.get(), 0, -(textWidth / 2) - padding, textHeight + (padding * 2) + arrowSize);
    363         CGPathAddLineToPoint(labelPath.get(), 0, -(textWidth / 2) - padding, arrowSize);
    364         CGPathAddLineToPoint(labelPath.get(), 0, -arrowSize, arrowSize);
    365         CGPathAddLineToPoint(labelPath.get(), 0, 0, 0);
    366         CGPathAddLineToPoint(labelPath.get(), 0, arrowSize, arrowSize);
    367         CGPathAddLineToPoint(labelPath.get(), 0, (textWidth / 2) + padding, arrowSize);
    368         CGPathAddLineToPoint(labelPath.get(), 0, (textWidth / 2) + padding, textHeight + (padding * 2) + arrowSize);
    369         textPosition = WebCore::FloatPoint(0, (textHeight / 2) + arrowSize + padding);
     358        switch (arrowEdgePosition) {
     359        case WebCore::InspectorOverlay::LabelArrowEdgePosition::Leading:
     360            textPosition = WebCore::FloatPoint((textWidth / 2) + padding, (textHeight / 2) + arrowSize + padding);
     361            break;
     362        case WebCore::InspectorOverlay::LabelArrowEdgePosition::Middle:
     363            textPosition = WebCore::FloatPoint(0, (textHeight / 2) + arrowSize + padding);
     364            break;
     365        case WebCore::InspectorOverlay::LabelArrowEdgePosition::Trailing:
     366            textPosition = WebCore::FloatPoint(-(textWidth / 2) - padding, (textHeight / 2) + arrowSize + padding);
     367            break;
     368        case WebCore::InspectorOverlay::LabelArrowEdgePosition::None:
     369            break;
     370        }
    370371        break;
    371372    case WebCore::InspectorOverlay::LabelArrowDirection::Right:
    372         CGPathMoveToPoint(labelPath.get(), 0, -textWidth - (padding * 2) - arrowSize, (textHeight / 2) + padding);
    373         CGPathAddLineToPoint(labelPath.get(), 0, -arrowSize, (textHeight / 2) + padding);
    374         CGPathAddLineToPoint(labelPath.get(), 0, -arrowSize, arrowSize);
    375         CGPathAddLineToPoint(labelPath.get(), 0, 0, 0);
    376         CGPathAddLineToPoint(labelPath.get(), 0, -arrowSize, -arrowSize);
    377         CGPathAddLineToPoint(labelPath.get(), 0, -arrowSize, -(textHeight / 2) - padding);
    378         CGPathAddLineToPoint(labelPath.get(), 0, -textWidth - (padding * 2) - arrowSize, -(textHeight / 2) - padding);
    379         textPosition = WebCore::FloatPoint(-(textWidth / 2) - arrowSize - padding, 0);
     373        switch (arrowEdgePosition) {
     374        case WebCore::InspectorOverlay::LabelArrowEdgePosition::Leading:
     375            textPosition = WebCore::FloatPoint(-(textWidth / 2) - arrowSize - padding, (textHeight / 2) + padding);
     376            break;
     377        case WebCore::InspectorOverlay::LabelArrowEdgePosition::Middle:
     378            textPosition = WebCore::FloatPoint(-(textWidth / 2) - arrowSize - padding, 0);
     379            break;
     380        case WebCore::InspectorOverlay::LabelArrowEdgePosition::Trailing:
     381            textPosition = WebCore::FloatPoint(-(textWidth / 2) - arrowSize - padding, -(textHeight / 2) - padding);
     382            break;
     383        case WebCore::InspectorOverlay::LabelArrowEdgePosition::None:
     384            break;
     385        }
    380386        break;
    381387    case WebCore::InspectorOverlay::LabelArrowDirection::Left:
    382         CGPathMoveToPoint(labelPath.get(), 0, textWidth + (padding * 2) + arrowSize, (textHeight / 2) + padding);
    383         CGPathAddLineToPoint(labelPath.get(), 0, arrowSize, (textHeight / 2) + padding);
    384         CGPathAddLineToPoint(labelPath.get(), 0, arrowSize, arrowSize);
    385         CGPathAddLineToPoint(labelPath.get(), 0, 0, 0);
    386         CGPathAddLineToPoint(labelPath.get(), 0, arrowSize, -arrowSize);
    387         CGPathAddLineToPoint(labelPath.get(), 0, arrowSize, -(textHeight / 2) - padding);
    388         CGPathAddLineToPoint(labelPath.get(), 0, textWidth + (padding * 2) + arrowSize, -(textHeight / 2) - padding);
    389         textPosition = WebCore::FloatPoint((textWidth / 2) + arrowSize + padding, 0);
     388        switch (arrowEdgePosition) {
     389        case WebCore::InspectorOverlay::LabelArrowEdgePosition::Leading:
     390            textPosition = WebCore::FloatPoint((textWidth / 2) + arrowSize + padding, (textHeight / 2) + padding);
     391            break;
     392        case WebCore::InspectorOverlay::LabelArrowEdgePosition::Middle:
     393            textPosition = WebCore::FloatPoint((textWidth / 2) + arrowSize + padding, 0);
     394            break;
     395        case WebCore::InspectorOverlay::LabelArrowEdgePosition::Trailing:
     396            textPosition = WebCore::FloatPoint((textWidth / 2) + arrowSize + padding, -(textHeight / 2) - padding);
     397            break;
     398        case WebCore::InspectorOverlay::LabelArrowEdgePosition::None:
     399            break;
     400        }
    390401        break;
    391402    case WebCore::InspectorOverlay::LabelArrowDirection::None:
    392         CGPathMoveToPoint(labelPath.get(), 0, 0, 0);
    393         CGPathAddLineToPoint(labelPath.get(), 0, 0, textHeight + (padding * 2));
    394         CGPathAddLineToPoint(labelPath.get(), 0, textWidth + (padding * 2), textHeight + (padding * 2));
    395         CGPathAddLineToPoint(labelPath.get(), 0, textWidth + (padding * 2), 0);
    396403        textPosition = WebCore::FloatPoint(padding + (textWidth / 2), padding + (textHeight / 2));
    397404        break;
    398405    }
    399406
    400     CGPathCloseSubpath(labelPath.get());
    401 
    402407    CALayer *layer = [CALayer layer];
    403408
     409#if USE(CG)
     410    // WebCore::Path::PlatformPathPtr is only a CGPath* when `USE(CG)` is true.
     411    auto labelPath = WebCore::InspectorOverlay::backgroundPathForLayoutLabel(textWidth + (padding * 2), textHeight + (padding * 2), arrowDirection, arrowEdgePosition, arrowSize);
     412    CGPath* platformLabelPath = labelPath.ensurePlatformPath();
     413
    404414    CAShapeLayer *labelPathLayer = [CAShapeLayer layer];
    405     labelPathLayer.path = labelPath.get();
     415    labelPathLayer.path = platformLabelPath;
    406416    labelPathLayer.fillColor = cachedCGColor(backgroundColor);
    407417    labelPathLayer.strokeColor = cachedCGColor(strokeColor);
    408418    labelPathLayer.position = CGPointMake(point.x(), point.y());
    409419    [layer addSublayer:labelPathLayer];
     420#endif
    410421
    411422    CATextLayer *textLayer = [CATextLayer layer];
     
    454465
    455466    for (auto area : overlay.areas)
    456         [layer addSublayer:createLayoutLabelLayer(area.name, area.quad.p1(), WebCore::InspectorOverlay::LabelArrowDirection::None, translucentLabelBackgroundColor, overlay.color, scale, area.quad.boundingBox().width())];
     467        [layer addSublayer:createLayoutLabelLayer(area.name, area.quad.p1(), WebCore::InspectorOverlay::LabelArrowDirection::None, WebCore::InspectorOverlay::LabelArrowEdgePosition::None, translucentLabelBackgroundColor, overlay.color, scale, area.quad.boundingBox().width())];
    457468
    458469    for (auto label : overlay.labels)
    459         [layer addSublayer:createLayoutLabelLayer(label.text, label.location, label.arrowDirection, label.backgroundColor, overlay.color, scale)];
     470        [layer addSublayer:createLayoutLabelLayer(label.text, label.location, label.arrowDirection, label.arrowEdgePosition, label.backgroundColor, overlay.color, scale)];
    460471
    461472    return layer;
Note: See TracChangeset for help on using the changeset viewer.