summaryrefslogtreecommitdiff
path: root/chromium/third_party/blink/renderer/core/inspector/inspect_tool_highlight.html
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/third_party/blink/renderer/core/inspector/inspect_tool_highlight.html')
-rw-r--r--chromium/third_party/blink/renderer/core/inspector/inspect_tool_highlight.html327
1 files changed, 288 insertions, 39 deletions
diff --git a/chromium/third_party/blink/renderer/core/inspector/inspect_tool_highlight.html b/chromium/third_party/blink/renderer/core/inspector/inspect_tool_highlight.html
index 2f9157c4a22..b5c7dbdb50f 100644
--- a/chromium/third_party/blink/renderer/core/inspector/inspect_tool_highlight.html
+++ b/chromium/third_party/blink/renderer/core/inspector/inspect_tool_highlight.html
@@ -66,7 +66,7 @@ body {
border-radius: 3px;
box-sizing: border-box;
min-width: 100px;
- max-width: 300px;
+ max-width: min(300px, 100% - 4px);
z-index: 1;
background-clip: padding-box;
will-change: transform;
@@ -87,6 +87,20 @@ body {
visibility: var(--arrow-visibility);
}
+.element-info-section {
+ margin-top: 12px;
+ margin-bottom: 6px;
+}
+
+.section-name {
+ color: #333;
+ font-weight: 500;
+ font-size: 10px;
+ text-transform: uppercase;
+ letter-spacing: .05em;
+ line-height: 12px;
+}
+
.element-info {
display: flex;
flex-direction: column;
@@ -109,13 +123,20 @@ body {
line-height: 19px;
}
-.element-info-contrast-row {
+.separator-container {
+ display: flex;
+ align-items: center;
+ flex: auto;
+ margin-left: 7px;
+}
+
+.separator {
border-top: 1px solid #ddd;
- padding-top: 5px;
- margin-top: 5px;
+ width: 100%;
}
.element-info-name {
+ flex-shrink: 0;
color: #666;
}
@@ -132,11 +153,21 @@ body {
.element-info-value-contrast {
display: flex;
+ align-items: center;
text-align: right;
color: rgb(48, 57, 66);
margin-left: 10px;
}
+.element-info-value-contrast .a11y-icon {
+ margin-left: 8px;
+}
+
+.element-info-value-icon {
+ display: flex;
+ align-items: center;
+}
+
.element-info-value-text {
text-align: right;
color: rgb(48, 57, 66);
@@ -205,16 +236,20 @@ body {
.a11y-icon {
width: 16px;
height: 16px;
- margin-left: 2px;
background-repeat: no-repeat;
+ display: inline-block;
+}
+
+.a11y-icon-not-ok {
+ background-image: url('data:image/svg+xml,<svg fill="none" viewBox="0 0 18 18" xmlns="http://www.w3.org/2000/svg"><path d="m9 1.5c-4.14 0-7.5 3.36-7.5 7.5s3.36 7.5 7.5 7.5 7.5-3.36 7.5-7.5-3.36-7.5-7.5-7.5zm0 13.5c-3.315 0-6-2.685-6-6 0-1.3875.4725-2.6625 1.2675-3.675l8.4075 8.4075c-1.0125.795-2.2875 1.2675-3.675 1.2675zm4.7325-2.325-8.4075-8.4075c1.0125-.795 2.2875-1.2675 3.675-1.2675 3.315 0 6 2.685 6 6 0 1.3875-.4725 2.6625-1.2675 3.675z" fill="%239e9e9e"/></svg>');
}
.a11y-icon-warning {
- background-image: url("data:image/svg+xml;charset=UTF-8, %3csvg xmlns='http://www.w3.org/2000/svg' width='16px' height='16px' viewBox='0 0 18 18' fill='%23ffc107'%3e%3cpath d='M0 0h18v18H0z' fill='none'/%3e%3cpath d='M.5 16h17L9 1 .5 16zm9.5-2H8v-2h2v2zm0-3H8V7h2v4z'/%3e%3c/svg%3e ");
+ background-image: url('data:image/svg+xml,<svg fill="none" viewBox="0 0 18 18" xmlns="http://www.w3.org/2000/svg"><path d="m8.25 11.25h1.5v1.5h-1.5zm0-6h1.5v4.5h-1.5zm.7425-3.75c-4.14 0-7.4925 3.36-7.4925 7.5s3.3525 7.5 7.4925 7.5c4.1475 0 7.5075-3.36 7.5075-7.5s-3.36-7.5-7.5075-7.5zm.0075 13.5c-3.315 0-6-2.685-6-6s2.685-6 6-6 6 2.685 6 6-2.685 6-6 6z" fill="%23e37400"/></svg>');
}
.a11y-icon-ok {
- background-image: url("data:image/svg+xml;charset=UTF-8, %3csvg xmlns='http://www.w3.org/2000/svg' width='16px' height='16px' viewBox='0 0 48 48' fill='%2300a000'%3e%3cpath d='M0 0h48v48H0z' fill='none'/%3e%3cpath d='M18 32.34L9.66 24l-2.83 2.83L18 38l24-24-2.83-2.83z'/%3e%3c/svg%3e");
+ background-image: url('data:image/svg+xml,<svg fill="none" viewBox="0 0 18 18" xmlns="http://www.w3.org/2000/svg"><path d="m9 1.5c-4.14 0-7.5 3.36-7.5 7.5s3.36 7.5 7.5 7.5 7.5-3.36 7.5-7.5-3.36-7.5-7.5-7.5zm0 13.5c-3.3075 0-6-2.6925-6-6s2.6925-6 6-6 6 2.6925 6 6-2.6925 6-6 6zm-1.5-4.35-1.95-1.95-1.05 1.05 3 3 6-6-1.05-1.05z" fill="%230ca40c"/></svg>');
}
@media (forced-colors: active) {
@@ -233,13 +268,14 @@ body {
}
.color-swatch-inner,
.contrast-text,
- .element-info-contrast-row {
+ .separator {
border-color: Highlight;
}
.dimensions,
.element-info-name,
.element-info-value-color,
.element-info-value-contrast,
+ .element-info-value-icon,
.element-info-value-text,
.material-tag-name,
.material-class-name,
@@ -407,14 +443,68 @@ function parseHexa(hexa) {
}
/**
- * @param {!String} hexa
+ * TODO(alexrudenko): import this and other color helpers from DevTools
+ * @param {!Array<number>} rgba
* @return {!Array<number>}
*/
-function normalizeColorString(hexa) {
- if (hexa.endsWith("FF"))
+function rgbaToHsla(rgba) {
+ const [r, g, b] = rgba;
+ const max = Math.max(r, g, b);
+ const min = Math.min(r, g, b);
+ const diff = max - min;
+ const sum = max + min;
+
+ let h;
+ if (min === max) {
+ h = 0;
+ } else if (r === max) {
+ h = ((1 / 6 * (g - b) / diff) + 1) % 1;
+ } else if (g === max) {
+ h = (1 / 6 * (b - r) / diff) + 1 / 3;
+ } else {
+ h = (1 / 6 * (r - g) / diff) + 2 / 3;
+ }
+
+ const l = 0.5 * sum;
+
+ let s;
+ if (l === 0) {
+ s = 0;
+ } else if (l === 1) {
+ s = 0;
+ } else if (l <= 0.5) {
+ s = diff / sum;
+ } else {
+ s = diff / (2 - sum);
+ }
+
+ return [h, s, l, rgba[3]];
+}
+
+/**
+ * @param {!String} hexa
+ * @param {!String} colorFormat
+ * @return {!String}
+ */
+function formatColor(hexa, colorFormat) {
+ if (colorFormat === 'rgb') {
+ const [r, g, b, a] = parseHexa(hexa);
+ // rgb(r g b [ / a])
+ return `rgb(${(r * 255).toFixed()} ${(g * 255).toFixed()} ${(b * 255).toFixed()}${a === 1 ? '' : ' / ' + Math.round(a * 100) / 100})`;
+ }
+
+ if (colorFormat === 'hsl') {
+ const [h, s, l, a] = rgbaToHsla(parseHexa(hexa));
+ // hsl(hdeg s l [ / a])
+ return `hsl(${Math.round(h * 360)}deg ${Math.round(s * 100)} ${Math.round(l * 100)}${a === 1 ? '' : ' / ' + Math.round(a * 100) / 100})`;
+ }
+
+ if (hexa.endsWith("FF")) {
+ // short hex if no alpha
return hexa.substr(0, 7);
- const [r, g, b, a] = parseHexa(hexa);
- return `rgba(${(r * 255).toFixed()}, ${(g * 255).toFixed()}, ${(b * 255).toFixed()}, ${Math.round(a * 100) / 100})`;
+ }
+
+ return hexa;
}
/**
@@ -484,7 +574,7 @@ function computeIsLargeFont(contrast) {
return fontSizePt >= 18;
}
-function _createElementDescription(elementInfo)
+function _createElementDescription(elementInfo, colorFormat)
{
const elementInfoElement = createElement("div", "element-info");
const elementInfoHeaderElement = elementInfoElement.createChild("div", "element-info-header");
@@ -513,7 +603,7 @@ function _createElementDescription(elementInfo)
const color = style["color"];
if (color && color !== "#00000000")
- addColorRow("Color", color);
+ addColorRow("Color", color, colorFormat);
const fontFamily = style["font-family"];
const fontSize = style["font-size"];
@@ -522,7 +612,7 @@ function _createElementDescription(elementInfo)
const bgcolor = style["background-color"];
if (bgcolor && bgcolor !== "#00000000")
- addColorRow("Background", bgcolor);
+ addColorRow("Background", bgcolor, colorFormat);
const margin = style["margin"];
if (margin && margin !== "0px")
@@ -533,12 +623,36 @@ function _createElementDescription(elementInfo)
addTextRow("Padding", padding);
const cbgColor = elementInfo.contrast ? elementInfo.contrast.backgroundColor : null;
- if (color && color !== "#00000000" && cbgColor && cbgColor !== "#00000000")
- addContrastRow(style["color"], elementInfo.contrast);
+ const hasContrastInfo = color && color !== "#00000000" && cbgColor && cbgColor !== "#00000000";
- function addRow(name, rowClassName, valueClassName) {
+ if (elementInfo.showAccessibilityInfo) {
+ addSection("Accessibility");
+
+ if (hasContrastInfo)
+ addContrastRow(style["color"], elementInfo.contrast);
+
+ addTextRow("Name", elementInfo.accessibleName);
+ addTextRow("Role", elementInfo.accessibleRole);
+ addIconRow("Keyboard-focusable", elementInfo.isKeyboardFocusable ? "a11y-icon a11y-icon-ok" : "a11y-icon a11y-icon-not-ok");
+ }
+
+ function ensureElementInfoBody() {
if (!elementInfoBodyElement)
elementInfoBodyElement = elementInfoElement.createChild("div", "element-info-body")
+ }
+
+ function addSection(name) {
+ ensureElementInfoBody();
+ const rowElement = elementInfoBodyElement.createChild("div", "element-info-row element-info-section");
+ const nameElement = rowElement.createChild("div", "section-name");
+ nameElement.textContent = name;
+ const separatorElement = rowElement
+ .createChild("div", "separator-container")
+ .createChild("div", "separator");
+ }
+
+ function addRow(name, rowClassName, valueClassName) {
+ ensureElementInfoBody();
const rowElement = elementInfoBodyElement.createChild("div", "element-info-row");
if (rowClassName)
rowElement.classList.add(rowClassName);
@@ -548,22 +662,26 @@ function _createElementDescription(elementInfo)
return rowElement.createChild("div", valueClassName || "");
}
+ function addIconRow(name, value) {
+ addRow(name, "", "element-info-value-icon").createChild('div', value);
+ }
+
function addTextRow(name, value) {
addRow(name, "", "element-info-value-text").createTextChild(value);
}
- function addColorRow(name, color) {
+ function addColorRow(name, color, colorFormat) {
const valueElement = addRow(name, "", "element-info-value-color");
const swatch = valueElement.createChild("div", "color-swatch");
const inner = swatch.createChild("div", "color-swatch-inner");
inner.style.backgroundColor = color;
- valueElement.createTextChild(normalizeColorString(color));
+ valueElement.createTextChild(formatColor(color, colorFormat));
}
function addContrastRow(fgColor, contrast) {
const ratio = contrastRatio(parseHexa(fgColor), parseHexa(contrast.backgroundColor));
const threshold = computeIsLargeFont(contrast) ? 3.0 : 4.5;
- const valueElement = addRow("Contrast", "element-info-contrast-row", "element-info-value-contrast");
+ const valueElement = addRow("Contrast", "", "element-info-value-contrast");
const sampleText = valueElement.createChild("div", "contrast-text");
sampleText.style.color = fgColor;
sampleText.style.backgroundColor = contrast.backgroundColor;
@@ -576,11 +694,11 @@ function _createElementDescription(elementInfo)
return elementInfoElement;
}
-function _drawElementTitle(elementInfo, bounds)
+function _drawElementTitle(elementInfo, bounds, colorFormat)
{
const tooltipContainer = document.getElementById("tooltip-container");
tooltipContainer.removeChildren();
- _createMaterialTooltip(tooltipContainer, bounds, _createElementDescription(elementInfo), true);
+ _createMaterialTooltip(tooltipContainer, bounds, _createElementDescription(elementInfo, colorFormat), true);
}
function _createMaterialTooltip(parentElement, bounds, contentElement, withArrow)
@@ -651,14 +769,17 @@ function _createMaterialTooltip(parentElement, bounds, contentElement, withArrow
tooltipContent.style.setProperty('--arrow-left', (arrowX - boxX) + 'px');
}
-function _drawRulers(context, bounds, rulerAtRight, rulerAtBottom)
+function _drawRulers(context, bounds, rulerAtRight, rulerAtBottom, color, dash)
{
context.save();
var width = canvasWidth;
var height = canvasHeight;
- context.strokeStyle = "rgba(128, 128, 128, 0.3)";
+ context.strokeStyle = color || "rgba(128, 128, 128, 0.3)";
context.lineWidth = 1;
context.translate(0.5, 0.5);
+ if (dash) {
+ context.setLineDash([3, 3]);
+ }
if (rulerAtRight) {
for (var y in bounds.rightmostXForY) {
@@ -779,22 +900,150 @@ function emptyBounds()
function _drawLayoutGridHighlight(highlight, context)
{
+ // Draw Grid border
+ if (highlight.gridHighlightConfig.gridBorderColor) {
+ context.save();
+ context.translate(0.5, 0.5);
+ context.lineWidth = 0;
+ if (highlight.gridHighlightConfig.gridBorderDash) {
+ context.setLineDash([3, 3]);
+ }
+ context.strokeStyle = highlight.gridHighlightConfig.gridBorderColor;
+ context.stroke(buildPath(highlight.gridBorder, emptyBounds()));
+ context.restore();
+ }
+
+ // Draw Cell Border
+ if (highlight.gridHighlightConfig.cellBorderColor) {
+ const rowBounds = emptyBounds();
+ const columnBounds = emptyBounds();
+ const rowPath = buildPath(highlight.rows, rowBounds);
+ const columnPath = buildPath(highlight.columns, columnBounds);
+ context.save();
+ context.translate(0.5, 0.5);
+ if (highlight.gridHighlightConfig.cellBorderDash) {
+ context.setLineDash([3, 3]);
+ }
+ context.lineWidth = 0;
+ context.strokeStyle = highlight.gridHighlightConfig.cellBorderColor;
+
+ context.save();
+ context.clip(columnPath);
+ context.stroke(rowPath);
+ context.restore();
+
+ context.save();
+ context.clip(rowPath);
+ context.stroke(columnPath);
+ context.restore();
+
+ context.restore();
+
+ if (highlight.gridHighlightConfig.showGridExtensionLines) {
+ // Extend row gap lines left/up.
+ _drawRulers(context, rowBounds, /* rulerAtRight */ false, /* rulerAtBottom */ false, highlight.gridHighlightConfig.cellBorderColor, highlight.gridHighlightConfig.cellBorderDash);
+ // Extend row gap right/down.
+ _drawRulers(context, rowBounds, /* rulerAtRight */ true, /* rulerAtBottom */ true, highlight.gridHighlightConfig.cellBorderColor, highlight.gridHighlightConfig.cellBorderDash);
+ // Extend column lines left/up.
+ _drawRulers(context, columnBounds, /* rulerAtRight */ false, /* rulerAtBottom */ false, highlight.gridHighlightConfig.cellBorderColor, highlight.gridHighlightConfig.cellBorderDash);
+ // Extend column right/down.
+ _drawRulers(context, columnBounds, /* rulerAtRight */ true, /* rulerAtBottom */ true, highlight.gridHighlightConfig.cellBorderColor, highlight.gridHighlightConfig.cellBorderDash);
+ }
+ }
+
+ // Row Gaps
+ if (highlight.gridHighlightConfig.rowGapColor) {
+ context.save();
+ context.translate(0.5, 0.5);
+ context.lineWidth = 0;
+ context.fillStyle = highlight.gridHighlightConfig.rowGapColor;
+ let bounds = emptyBounds();
+ const path = buildPath(highlight.rowGaps, bounds);
+ if (highlight.gridHighlightConfig.rowHatchColor) {
+ hatchFillPath(context, path, bounds, 10, highlight.gridHighlightConfig.rowHatchColor, /* flipDirection */ true);
+ }
+ context.fill(path);
+ context.restore();
+ }
+
+ // Column Gaps
+ if (highlight.gridHighlightConfig.columnGapColor) {
+ context.save();
+ context.translate(0.5, 0.5);
+ context.lineWidth = 0;
+ context.fillStyle = highlight.gridHighlightConfig.columnGapColor;
+ let bounds = emptyBounds();
+ const path = buildPath(highlight.columnGaps, bounds);
+ if (highlight.gridHighlightConfig.columnHatchColor) {
+ hatchFillPath(context, path, bounds, 10, highlight.gridHighlightConfig.columnHatchColor);
+ }
+ context.fill(path);
+ context.restore();
+ }
+}
+
+/**
+ * Draw line hatching at a 45 degree angle for a given
+ * path.
+ * __________
+ * |\ \ \ |
+ * | \ \ \|
+ * | \ \ |
+ * |\ \ \ |
+ * **********
+ *
+ * @param {CanvasRenderingContext2D} context
+ * @param {Path2D} path
+ * @param {Object} bounds
+ * @param {delta} delta - vertical gap between hatching lines in pixels
+ * @param {string} color
+ * @param {boolean=} flipDirection - lines are drawn from top right to bottom left
+ *
+ */
+function hatchFillPath(context, path, bounds, delta, color, flipDirection) {
+ const dx = bounds.maxX - bounds.minX;
+ const dy = bounds.maxY - bounds.minY;
+ context.rect(bounds.minX, bounds.minY, dx, dy);
context.save();
- context.translate(0.5, 0.5);
- context.setLineDash([3, 3]);
- context.lineWidth = 0;
- context.strokeStyle = highlight.color;
- context.stroke(buildPath(highlight.cells, emptyBounds()));
+ context.clip(path);
+ context.setLineDash([5, 3]);
+ const majorAxis = Math.max(dx, dy);
+ context.strokeStyle = color;
+ if (flipDirection) {
+ for (let i = -majorAxis; i < majorAxis; i += delta) {
+ context.beginPath();
+ context.moveTo(bounds.maxX - i , bounds.minY);
+ context.lineTo(bounds.maxX - dy - i, bounds.maxY);
+ context.stroke();
+ }
+ } else {
+ for (let i = -majorAxis; i < majorAxis; i += delta) {
+ context.beginPath();
+ context.moveTo(i + bounds.minX, bounds.minY);
+ context.lineTo(dy + i + bounds.minX, bounds.maxY);
+ context.stroke();
+ }
+ }
context.restore();
}
-function clipLayoutGridCells(highlight) {
+function clipLayoutGridCells(highlight, context) {
+ // It may seem simpler to, before drawing the desired path, call context.clip()
+ // with the rows and then with the columns. However, the 2nd context.clip() call
+ // would try to find the intersection of the rows and columns, which is way too
+ // expensive if the grid is huge, e.g. a 1000x1000 grid has 1M cells.
+ // Therefore, it's better to draw the path first, set the globalCompositeOperation
+ // so that the existing canvas content is kept where it overlaps with new content,
+ // and then draw the rows and columns.
if (highlight.gridInfo) {
for (const grid of highlight.gridInfo) {
if (!grid.isPrimaryGrid)
continue;
- const path = buildPath(grid.cells, emptyBounds());
- context.clip(path);
+ context.save();
+ context.globalCompositeOperation = "destination-in";
+ drawPath(context, grid.rows, "red", null, emptyBounds());
+ drawPath(context, grid.columns, "red", null, emptyBounds());
+ context.restore();
}
}
}
@@ -808,15 +1057,15 @@ function drawHighlight(highlight, context)
for (var paths = highlight.paths.slice(); paths.length;) {
var path = paths.pop();
- // Clip content quad using the data grid cells info to create white stripes.
context.save();
- if (path.name === "content")
- clipLayoutGridCells(highlight);
drawPath(context, path.path, path.fillColor, path.outlineColor, bounds);
if (paths.length) {
context.globalCompositeOperation = "destination-out";
drawPath(context, paths[paths.length - 1].path, "red", null, bounds);
}
+ // Clip content quad using the data grid cells info to create white stripes.
+ if (path.name === "content")
+ clipLayoutGridCells(highlight, context);
context.restore();
}
context.restore();
@@ -834,7 +1083,7 @@ function drawHighlight(highlight, context)
_drawRulers(context, bounds, rulerAtRight, rulerAtBottom);
if (highlight.elementInfo)
- _drawElementTitle(highlight.elementInfo, bounds);
+ _drawElementTitle(highlight.elementInfo, bounds, highlight.colorFormat);
}
if (highlight.gridInfo) {
for (var grid of highlight.gridInfo)
@@ -851,7 +1100,7 @@ function test() {
drawHighlight(
{"paths":[{"path":["M",122,133.796875,"L",822,133.796875,"L",822,208.796875,"L",122,208.796875,"Z"], "fillColor":"rgba(111, 168, 220, 0.658823529411765)","name":"content"},
{"path":["M",122,113.796875,"L",822,113.796875,"L",822,228.796875,"L",122,228.796875,"Z"],"fillColor":"rgba(246, 178, 107, 0.66)","name":"margin"}],"showRulers":false,"showExtensionLines":false,
- "elementInfo":{"tagName":"button","className":"class.name", "idValue":"download-hero","nodeWidth":"700","nodeHeight":"75","style":{"color":"#FFFFFFFF","font-family":"\"Product Sans\", \"Open Sans\", Roboto, Arial, \"Product Sans\", \"Open Sans\", Roboto, Arial","font-size":"20px","line-height":"25px","padding":"0px","margin":"20px 0px","background-color":"#00000000"},"contrast":{"fontSize":"20px","fontWeight":"400","backgroundColor":"#F9B826BF"}}, showExtensionLines: true, showRulers: true});
+ "elementInfo":{"tagName":"button","className":"class.name", "idValue":"download-hero","nodeWidth":"700","nodeHeight":"75","style":{"color":"#FFFFFFFF","font-family":"\"Product Sans\", \"Open Sans\", Roboto, Arial, \"Product Sans\", \"Open Sans\", Roboto, Arial","font-size":"20px","line-height":"25px","padding":"0px","margin":"20px 0px","background-color":"#00000000"},"contrast":{"fontSize":"20px","fontWeight":"400","backgroundColor":"#F9B826BF"},"isKeyboardFocusable":false,"accessibleName":"name","accessibleRole":"role","showAccessibilityInfo":true}, showExtensionLines: true, showRulers: true, colorFormat: "hsl"});
}
</script>