Diff
Modified: trunk/Source/WebCore/ChangeLog (290111 => 290112)
--- trunk/Source/WebCore/ChangeLog 2022-02-18 04:52:02 UTC (rev 290111)
+++ trunk/Source/WebCore/ChangeLog 2022-02-18 05:21:37 UTC (rev 290112)
@@ -1,3 +1,32 @@
+2022-02-17 Patrick Angle <[email protected]>
+
+ Web Inspector: [Flexbox] Add indicators for layout context in element tooltips
+ https://bugs.webkit.org/show_bug.cgi?id=236738
+
+ Reviewed by Devin Rousso.
+
+ * en.lproj/Localizable.strings:
+ * inspector/InspectorOverlay.cpp:
+ (WebCore::rendererIsFlexboxItem):
+ (WebCore::rendererIsGridItem):
+ (WebCore::InspectorOverlay::drawElementTitle):
+ - Add new `Flex Item`, `Flex`, `Grid Item`, and `Grid` bubblea to element tooltips to allow provide more
+ context about layout while selecting nodes on a page.
+ - Move the role into its own bubble with special color (based on the previous coloring of the `Role` text).
+
+ * inspector/InspectorOverlayLabel.cpp:
+ (WebCore::InspectorOverlayLabel::draw):
+ * inspector/InspectorOverlayLabel.h:
+ (WebCore::InspectorOverlayLabel::Content::encode const):
+ (WebCore::InspectorOverlayLabel::Content::decode):
+ (WebCore::InspectorOverlayLabel::Content::Decoration::encode const):
+ (WebCore::InspectorOverlayLabel::Content::Decoration::decode):
+ - Add the concept of text decoration (currently just bordered text).
+ - Create an intermediate `ComputedContentRun` to hold the intermediate representation of content with the
+ computed attributes of each piece of text. This allows us to better scale with the addition of the new text
+ decorations and other configuration properties instead of having to create even more Vectors of things that need
+ to be kept in sync with each other.
+
2022-02-17 Simon Fraser <[email protected]>
Crash under ScrollingCoordinatorMac::hasNodeWithAnimatedScrollChanged()
Modified: trunk/Source/WebCore/en.lproj/Localizable.strings (290111 => 290112)
--- trunk/Source/WebCore/en.lproj/Localizable.strings 2022-02-18 04:52:02 UTC (rev 290111)
+++ trunk/Source/WebCore/en.lproj/Localizable.strings 2022-02-18 05:21:37 UTC (rev 290112)
@@ -478,6 +478,12 @@
/* Default application name for Open With context menu */
"Finder" = "Finder";
+/* Inspector element selection tooltip text for Flexbox containers. */
+"Flex (Inspector Element Selection)" = "Flex";
+
+/* Inspector element selection tooltip text for items inside a Flexbox Container. */
+"Flex Item (Inspector Element Selection)" = "Flex Item";
+
/* Font context sub-menu item */
"Font" = "Font";
@@ -502,6 +508,12 @@
/* Google Safe Browsing */
"Google Safe Browsing" = "Google Safe Browsing";
+/* Inspector element selection tooltip text for Grid containers. */
+"Grid (Inspector Element Selection)" = "Grid";
+
+/* Inspector element selection tooltip text for items inside a Grid Container. */
+"Grid Item (Inspector Element Selection)" = "Grid Item";
+
/* accessibility role description for web area */
"HTML content" = "HTML content";
Modified: trunk/Source/WebCore/inspector/InspectorOverlay.cpp (290111 => 290112)
--- trunk/Source/WebCore/inspector/InspectorOverlay.cpp 2022-02-18 04:52:02 UTC (rev 290111)
+++ trunk/Source/WebCore/inspector/InspectorOverlay.cpp 2022-02-18 05:21:37 UTC (rev 290112)
@@ -56,6 +56,7 @@
#include "IntPoint.h"
#include "IntRect.h"
#include "IntSize.h"
+#include "LocalizedStrings.h"
#include "Node.h"
#include "NodeList.h"
#include "NodeRenderStyle.h"
@@ -1019,6 +1020,22 @@
}
}
+static bool rendererIsFlexboxItem(RenderObject& renderer)
+{
+ if (auto* parentFlexRenderer = dynamicDowncast<RenderFlexibleBox>(renderer.parent()))
+ return !parentFlexRenderer->orderIterator().shouldSkipChild(renderer);
+
+ return false;
+}
+
+static bool rendererIsGridItem(RenderObject& renderer)
+{
+ if (is<RenderGrid>(renderer.parent()))
+ return !renderer.isOutOfFlowPositioned() && !renderer.isExcludedFromNormalLayout();
+
+ return false;
+}
+
Path InspectorOverlay::drawElementTitle(GraphicsContext& context, Node& node, const InspectorOverlay::Highlight::Bounds& bounds)
{
if (bounds.isEmpty())
@@ -1072,6 +1089,18 @@
elementHeight = String::number(boundingBox.height());
}
+ Vector<String> layoutContextBubbleStrings;
+
+ if (rendererIsFlexboxItem(*renderer))
+ layoutContextBubbleStrings.append(WEB_UI_STRING_KEY("Flex Item", "Flex Item (Inspector Element Selection)", "Inspector element selection tooltip text for items inside a Flexbox Container."));
+ else if (rendererIsGridItem(*renderer))
+ layoutContextBubbleStrings.append(WEB_UI_STRING_KEY("Grid Item", "Grid Item (Inspector Element Selection)", "Inspector element selection tooltip text for items inside a Grid Container."));
+
+ if (is<RenderFlexibleBox>(renderer))
+ layoutContextBubbleStrings.append(WEB_UI_STRING_KEY("Flex", "Flex (Inspector Element Selection)", "Inspector element selection tooltip text for Flexbox containers."));
+ else if (is<RenderGrid>(renderer))
+ layoutContextBubbleStrings.append(WEB_UI_STRING_KEY("Grid", "Grid (Inspector Element Selection)", "Inspector element selection tooltip text for Grid containers."));
+
// Need to enable AX to get the computed role.
if (!WebCore::AXObjectCache::accessibilityEnabled())
WebCore::AXObjectCache::enableAccessibility();
@@ -1085,7 +1114,8 @@
constexpr auto elementTitleTagColor = SRGBA<uint8_t> { 136, 18, 128 }; // Keep this in sync with XMLViewer.css (.tag)
constexpr auto elementTitleAttributeValueColor = SRGBA<uint8_t> { 26, 26, 166 }; // Keep this in sync with XMLViewer.css (.attribute-value)
constexpr auto elementTitleAttributeNameColor = SRGBA<uint8_t> { 153, 69, 0 }; // Keep this in sync with XMLViewer.css (.attribute-name)
- constexpr auto elementTitleRoleColor = SRGBA<uint8_t> { 170, 13, 145 };
+ constexpr auto elementTitleRoleBubbleColor = SRGBA<uint8_t> { 170, 13, 145, 48 };
+ constexpr auto elementTitleLayoutBubbleColor = Color::gray.colorWithAlphaByte(64);
Vector<InspectorOverlayLabel::Content> labelContents = {
{ elementTagName, elementTitleTagColor },
@@ -1098,9 +1128,19 @@
{ "px"_s, Color::darkGray },
};
- if (!elementRole.isEmpty()) {
- labelContents.append({ "\nRole "_s, elementTitleRoleColor });
- labelContents.append({ elementRole, Color::black });
+ if (!elementRole.isEmpty() || !layoutContextBubbleStrings.isEmpty()) {
+ labelContents.append({ "\n"_s, Color::black });
+
+ if (!elementRole.isEmpty())
+ labelContents.append({ makeString("Role: "_s, elementRole), Color::black, { InspectorOverlayLabel::Content::Decoration::Type::Bordered, elementTitleRoleBubbleColor } });
+
+ auto isFirstBubble = elementRole.isEmpty();
+ for (auto& layoutContextBubbleString : layoutContextBubbleStrings) {
+ if (!isFirstBubble)
+ labelContents.append({ " "_s, Color::black });
+ labelContents.append({ layoutContextBubbleString, Color::black, { InspectorOverlayLabel::Content::Decoration::Type::Bordered, elementTitleLayoutBubbleColor } });
+ isFirstBubble = false;
+ }
}
FrameView* pageView = m_page.mainFrame().view();
Modified: trunk/Source/WebCore/inspector/InspectorOverlayLabel.cpp (290111 => 290112)
--- trunk/Source/WebCore/inspector/InspectorOverlayLabel.cpp 2022-02-18 04:52:02 UTC (rev 290111)
+++ trunk/Source/WebCore/inspector/InspectorOverlayLabel.cpp 2022-02-18 05:21:37 UTC (rev 290112)
@@ -29,6 +29,7 @@
#include "config.h"
#include "InspectorOverlayLabel.h"
+#include "FloatRoundedRect.h"
#include "FloatSize.h"
#include "FontCascade.h"
#include "FontCascadeDescription.h"
@@ -39,6 +40,8 @@
static constexpr float labelPadding = 4;
static constexpr float labelArrowSize = 6;
+static constexpr float labelAdditionalLineSpacing = 1;
+static constexpr float labelContentDecorationBorderedLeadingAndTrailingPadding = 1;
InspectorOverlayLabel::InspectorOverlayLabel(Vector<Content>&& contents, FloatPoint location, Color backgroundColor, Arrow arrow)
: m_contents(WTFMove(contents))
@@ -193,6 +196,14 @@
return path;
}
+struct ComputedContentRun {
+ TextRun textRun;
+ Color textColor;
+ InspectorOverlayLabel::Content::Decoration decoration;
+ bool startsNewLine;
+ float computedWidth;
+};
+
Path InspectorOverlayLabel::draw(GraphicsContext& context, float maximumLineWidth)
{
constexpr UChar ellipsis = 0x2026;
@@ -201,10 +212,8 @@
float lineHeight = font.metricsOfPrimaryFont().floatHeight();
float lineDescent = font.metricsOfPrimaryFont().floatDescent();
- Vector<TextRun> textRuns;
- Vector<Color> textColors;
- Vector<float> textWidths;
- Vector<size_t> lineStartIndexes;
+ Vector<ComputedContentRun> computedContentRuns;
+
float longestLineWidth = 0;
int currentLine = 0;
@@ -211,17 +220,17 @@
float currentLineWidth = 0;
for (auto content : m_contents) {
auto lines = content.text.splitAllowingEmptyEntries('\n');
+
+ ASSERT(content.decoration.type == Content::Decoration::Type::None || lines.size() <= 1);
+
for (size_t i = 0; i < lines.size(); ++i) {
- if (i) {
- lineStartIndexes.append(textRuns.size());
+ auto startsNewLine = !!i;
+ if (startsNewLine) {
currentLineWidth = 0;
++currentLine;
}
auto text = lines[i];
- if (text.isEmpty())
- continue;
-
auto textRun = TextRun(text);
float textWidth = font.width(textRun);
@@ -235,9 +244,7 @@
}
}
- textRuns.append(WTFMove(textRun));
- textColors.append(content.textColor);
- textWidths.append(textWidth);
+ computedContentRuns.append({ textRun, content.textColor, content.decoration, startsNewLine, textWidth });
currentLineWidth += textWidth;
if (currentLineWidth > longestLineWidth)
@@ -245,7 +252,7 @@
}
}
- float totalTextHeight = lineHeight * (currentLine + 1);
+ float totalTextHeight = (lineHeight * (currentLine + 1)) + (currentLine * labelAdditionalLineSpacing);
FloatPoint textPosition;
switch (m_arrow.direction) {
@@ -325,16 +332,42 @@
int line = 0;
float xOffset = 0;
- for (size_t i = 0; i < textRuns.size(); ++i) {
- if (lineStartIndexes.contains(i)) {
+ float yOffset = 0;
+ for (auto& computedContentRun : computedContentRuns) {
+ if (computedContentRun.startsNewLine) {
xOffset = 0;
++line;
+ yOffset += lineHeight + labelAdditionalLineSpacing;
}
- context.setFillColor(textColors[i]);
- context.drawText(font, textRuns[i], textPosition + FloatPoint(xOffset, line * lineHeight));
+ switch (computedContentRun.decoration.type) {
+ case Content::Decoration::Type::Bordered: {
+ auto backgroundRect = FloatRoundedRect({
+ textPosition.x() + xOffset - labelContentDecorationBorderedLeadingAndTrailingPadding,
+ textPosition.y() + yOffset - lineHeight + lineDescent,
+ computedContentRun.computedWidth + (labelContentDecorationBorderedLeadingAndTrailingPadding * 2),
+ lineHeight,
+ }, FloatRoundedRect::Radii(2));
- xOffset += textWidths[i];
+ Path backgroundPath;
+ backgroundPath.addRoundedRect(backgroundRect);
+
+ context.setFillColor(computedContentRun.decoration.color);
+ context.setStrokeColor(computedContentRun.decoration.color.darkened());
+
+ context.fillPath(backgroundPath);
+ context.strokePath(backgroundPath);
+ break;
+ }
+
+ case Content::Decoration::Type::None:
+ break;
+ }
+
+ context.setFillColor(computedContentRun.textColor);
+ context.drawText(font, computedContentRun.textRun, textPosition + FloatPoint(xOffset, yOffset));
+
+ xOffset += computedContentRun.computedWidth;
}
return labelPath;
@@ -367,7 +400,7 @@
}
}
- float totalTextHeight = lineHeight * (currentLine + 1);
+ float totalTextHeight = (lineHeight * (currentLine + 1)) + (currentLine * labelAdditionalLineSpacing);
switch (direction) {
case Arrow::Direction::Down:
Modified: trunk/Source/WebCore/inspector/InspectorOverlayLabel.h (290111 => 290112)
--- trunk/Source/WebCore/inspector/InspectorOverlayLabel.h 2022-02-18 04:52:02 UTC (rev 290111)
+++ trunk/Source/WebCore/inspector/InspectorOverlayLabel.h 2022-02-18 05:21:37 UTC (rev 290112)
@@ -79,8 +79,24 @@
struct Content {
WTF_MAKE_STRUCT_FAST_ALLOCATED;
+ struct Decoration {
+ enum class Type : uint8_t {
+ None,
+ Bordered,
+ };
+
+ Type type;
+ Color color;
+
+#if PLATFORM(IOS_FAMILY)
+ template<class Encoder> void encode(Encoder&) const;
+ template<class Decoder> static std::optional<InspectorOverlayLabel::Content::Decoration> decode(Decoder&);
+#endif
+ };
+
String text;
Color textColor;
+ Decoration decoration { Decoration::Type::None, Color::transparentBlack };
#if PLATFORM(IOS_FAMILY)
template<class Encoder> void encode(Encoder&) const;
@@ -173,6 +189,7 @@
{
encoder << text;
encoder << textColor;
+ encoder << decoration;
}
template<class Decoder> std::optional<InspectorOverlayLabel::Content> InspectorOverlayLabel::Content::decode(Decoder& decoder)
@@ -187,9 +204,35 @@
if (!textColor)
return std::nullopt;
- return { { *text, *textColor } };
+ std::optional<Decoration> decoration;
+ decoder >> decoration;
+ if (!decoration)
+ return std::nullopt;
+
+ return { { *text, *textColor, *decoration } };
}
+template<class Encoder> void InspectorOverlayLabel::Content::Decoration::encode(Encoder& encoder) const
+{
+ encoder << type;
+ encoder << color;
+}
+
+template<class Decoder> std::optional<InspectorOverlayLabel::Content::Decoration> InspectorOverlayLabel::Content::Decoration::decode(Decoder& decoder)
+{
+ std::optional<Type> type;
+ decoder >> type;
+ if (!type)
+ return std::nullopt;
+
+ std::optional<Color> color;
+ decoder >> color;
+ if (!color)
+ return std::nullopt;
+
+ return { { *type, *color } };
+}
+
#endif
} // namespace WebCore
@@ -217,4 +260,12 @@
>;
};
+template<> struct EnumTraits<WebCore::InspectorOverlayLabel::Content::Decoration::Type> {
+ using values = EnumValues<
+ WebCore::InspectorOverlayLabel::Content::Decoration::Type,
+ WebCore::InspectorOverlayLabel::Content::Decoration::Type::None,
+ WebCore::InspectorOverlayLabel::Content::Decoration::Type::Bordered
+ >;
+};
+
}