blob: 2647f22c45d6d56667c901599111fc14c3acb0cc [file] [log] [blame]
var shouldAutoDump = true;
(function () {
if (window.testRunner)
testRunner.dumpAsText();
window.dumpAttributedString = function dumpAttributedString(root = document.body, startContainer, startOffset, endContainer, endOffset) {
shouldAutoDump = false;
const markup = serializeSubtreeWithShadow(root, startContainer, startOffset, endContainer, endOffset).trim();
if (!startContainer)
startContainer = root;
if (startOffset == undefined)
startOffset = 0;
if (!endContainer)
endContainer = root;
if (endOffset == undefined)
endOffset = endContainer.childNodes.length;
const pre = document.createElement('pre');
const result = serializeAttributedString(textInputController.legacyAttributedString(startContainer, startOffset, endContainer, endOffset));
pre.textContent = 'Input:\n' + markup + '\n\nOutput:\n' + result;
document.body.innerHTML = '';
document.body.appendChild(pre);
}
function serializeSubtreeWithShadow(parent, startContainer, startOffset, endContainer, endOffset) {
function serializeCharacterData(node) {
let data = node.data;
let result = data;
if (node == startContainer && node == endContainer) {
result = data.substring(0, startOffset);
result += '<#start>';
result = data.substring(startOffset, endOffset);
result += '<#end>';
result += data.substring(endOffset);
} else if (node == startContainer) {
result = data.substring(0, startOffset);
result += '<#start>';
result += data.substring(startOffset);
} else if (node == endContainer) {
result = data.substring(0, endOffset);
result += '<#end>';
result += data.substring(endOffset);
}
return result;
}
function serializeNode(node) {
if (node.nodeType == Node.TEXT_NODE)
return serializeCharacterData(node);
if (node.nodeType == Node.COMMENT_NODE)
return '<!--' + node.nodeValue + '-->';
if (node.nodeType == Node.CDATA_SECTION_NODE)
return '<!--[CDATA[' + node.nodeValue + '-->';
const elementTags = node.cloneNode(false).outerHTML;
const endTagIndex = elementTags.lastIndexOf('</');
const startTag = endTagIndex >= 0 ? elementTags.substring(0, endTagIndex) : elementTags;
const endTag = endTagIndex >= 0 ? elementTags.substring(endTagIndex) : '';
return startTag + serializeShadowRootAndChildNodes(node) + endTag;
}
function serializeChildNodes(node) {
let result = '';
for (let i = 0; i < node.childNodes.length; i++) {
if (node == startContainer && i == startOffset)
result += '<#start>';
result += serializeNode(node.childNodes[i]);
if (node == endContainer && i + 1 == endOffset)
result += '<#end>';
}
return result;
}
function serializeShadowRootAndChildNodes(node) {
const shadowRoot = node.nodeType == Node.ELEMENT_NODE ? internals.shadowRoot(node) : null;
if (!shadowRoot)
return serializeChildNodes(node);
return `<#shadow-start>${serializeChildNodes(shadowRoot)}<#shadow-end>${serializeChildNodes(node)}`;
}
return serializeShadowRootAndChildNodes(parent);
}
window.serializeAttributedString = function (attributedString) {
var string = attributedString.string();
var output = '';
function log(text) {
output += text + '\n';
}
var currentParagraphStyle;
attributedString.ranges().forEach(function (range) {
var location = range.location();
var length = range.length();
var attributeNames = attributedString.getAttributeNamesAtIndex(location, length).slice();
if (attributeNames.indexOf('NSParagraphStyle') >= 0) {
var value = '' + attributedString.getAttributeValueAtIndex('NSParagraphStyle', location);
var newParagraphStyle = value.split(', ').reduce(function (result, component) {
var match = component.match(/(\w+)\s+([^]+)/);
return (result ? result + '\n' : '') + ' ' + match[1] + ': ' + formatParagraphStyle(match[1], match[2]);
});
if (newParagraphStyle != currentParagraphStyle) {
log('NSParagraphStyle:');
log(newParagraphStyle);
currentParagraphStyle = newParagraphStyle;
}
}
log('[' + string.substring(location, location + length).replace('\n', '\\n') + ']');
attributeNames.sort().forEach(function (attributeName) {
var indentAndName = ' ' + attributeName + ':';
var value = '' + attributedString.getAttributeValueAtIndex(attributeName, location);
if (attributeName != 'NSParagraphStyle')
log(indentAndName + ' ' + formatNonParagraphAttributeValue(attributeName, value));
});
});
return output;
}
function formatNonParagraphAttributeValue(name, value) {
value = value.replace(/^"|"$/g, '');
switch (name) {
case 'NSFont':
return value.match(/(.+?)\s+P \[\]/)[1];
case 'NSColor':
case 'NSStrokeColor':
case 'NSBackgroundColor':
var parsed = parseNSColorDescription(value);
return serializeColor(parsed.rgb, parsed.alpha) + ' (' + parsed.colorSpace + ')';
case 'NSUnderline':
case 'NSStrikethrough':
switch (value) {
case '1':
return 'true';
case '0':
return 'false';
}
return value;
case 'NSKern':
return value + 'pt';
}
return value;
}
function parseNSColorDescription(value) {
var match = value.match(/^\s*(\w+).+\s([0-9\.]+)\s+([0-9\.]+)\s+([0-9\.]+)\s+([0-9\.]+)\s*$/);
return {
colorSpace: match[1],
rgb: match.slice(2, 5).map(function (string) { return Math.round(string * 255); }),
alpha: match[5],
};
}
function serializeColor(rgb, alpha) {
if (alpha == 1)
return '#' + rgb.map(function (component) {
var digits = component.toString(16);
return digits.length < 2 ? '0' + digits : digits;
}).join('');
return 'rgba(' + rgb.concat(alpha).join(', ') + ')';
}
function formatParagraphStyle(name, value) {
switch (name) {
case 'Alignment':
switch (parseInt(value)) {
case 0:
return 'left';
case 1:
return 'right';
case 2:
return 'center';
case 3:
return 'justified';
case 4:
return 'natural';
}
break;
case 'Tabs':
return value.replace('\n', '');
}
return value;
}
window.onload = function () {
if (shouldAutoDump)
dumpAttributedString();
}
})();