diff options
author | Andy Huang <ath@google.com> | 2013-03-08 13:50:36 -0800 |
---|---|---|
committer | Andy Huang <ath@google.com> | 2013-03-08 13:50:36 -0800 |
commit | 3a398b245930ce60ceb51fc605ab0f20c8df1f62 (patch) | |
tree | 5da7a79eb8cce754576d890f3fa986e1af39f835 /assets | |
parent | 5ea5a8330532a75c83cbb30993a14ee9b821fa2a (diff) | |
download | android_packages_apps_UnifiedEmail-3a398b245930ce60ceb51fc605ab0f20c8df1f62.tar.gz android_packages_apps_UnifiedEmail-3a398b245930ce60ceb51fc605ab0f20c8df1f62.tar.bz2 android_packages_apps_UnifiedEmail-3a398b245930ce60ceb51fc605ab0f20c8df1f62.zip |
reverse ineffective HTML transforms, add aggressive <td> transform
Reverse <table> and <td> transform work when the resulting width is
unchanged, or significantly unchanged (below a threshold).
Switch <table> and <td> transforms to use CSS !important overriding
instead of modifying the elements inline. This is easier to reverse.
Add another <td> transform to aggressively trigger word wrapping intra-
word. This helps break long signatures, but it can render complex
promotional email unreadable. I'll have to hide this behind a classifier
that prevents this from running on complex messages.
Bug: 7400516
Change-Id: Ia17bae2b28eeec9d1cd40d0292380ae5d660586d
Diffstat (limited to 'assets')
-rw-r--r-- | assets/script.js | 109 |
1 files changed, 91 insertions, 18 deletions
diff --git a/assets/script.js b/assets/script.js index acf219002..c4f3ae6d2 100644 --- a/assets/script.js +++ b/assets/script.js @@ -24,6 +24,13 @@ var gImageLoadElements = []; var gScaleInfo; /** + * Only revert transforms that do an imperfect job of shrinking content if they fail + * to shrink by this much. Expressed as a ratio of: + * (original width difference : width difference after transforms); + */ +TRANSFORM_MINIMUM_EFFECTIVE_RATIO = 0.75; + +/** * Returns the page offset of an element. * * @param {Element} element The element to return the page offset for. @@ -188,51 +195,117 @@ function normalizeElementWidths(elements) { function mungeTables(el, docWidth, elWidth) { var nodes; var i, len; - var newWidth; + var newWidth = elWidth; var wStr; - var touched = false; + var touched; + var actionLog = []; + var node; + var start; if (elWidth <= docWidth) { return; } - // first find tables with widths and strip them of widths - nodes = el.querySelectorAll("table[width]"); + + start = Date.now(); + // Try munging all divs with inline styles where the width + // is wider than docWidth, and change it to be a max-width. + touched = false; + nodes = el.querySelectorAll("div[style]"); for (i = 0, len = nodes.length; i < len; i++) { - if (nodes[i].hasAttribute("width")) { - nodes[i].removeAttribute("width"); + node = nodes[i]; + wStr = node.style.width; + if (wStr && wStr.slice(0, -2) > docWidth) { + node.style.width = ""; + node.style.maxWidth = wStr; touched = true; } } if (touched) { newWidth = el.scrollWidth; + console.log("ran div-width munger on el=" + el + " oldW=" + elWidth + " newW=" + newWidth + + " docW=" + docWidth); + if (newWidth <= docWidth) { + console.log("munger succeeded, elapsed time=" + (Date.now() - start)); + return; + } + } + + // OK, that wasn't enough. Find tables with widths and override their widths. + touched = addClassToElements(el.querySelectorAll("table"), shouldMungeTable, "munged", + actionLog); + if (touched) { + newWidth = el.scrollWidth; console.log("ran table munger on el=" + el + " oldW=" + elWidth + " newW=" + newWidth + " docW=" + docWidth); if (newWidth <= docWidth) { + console.log("munger succeeded, elapsed time=" + (Date.now() - start)); return; } } - // OK, that wasn't enough. Try munging all divs with inline styles where the width - // is wider than docWidth, and change it to be a max-width. - touched = false; - nodes = el.querySelectorAll("div[style]"); - for (i = 0, len = nodes.length; i < len; i++) { - wStr = nodes[i].style.width; - if (wStr && wStr.slice(0, -2) > docWidth) { - nodes[i].style.width = ""; - nodes[i].style.maxWidth = wStr; - touched = true; + // OK, that wasn't enough. Try munging all <td> to override any width and nowrap set. + touched = addClassToElements(el.querySelectorAll("td"), null /* mungeAll */, "munged", + actionLog); + if (touched) { + newWidth = el.scrollWidth; + console.log("ran td munger on el=" + el + " oldW=" + elWidth + " newW=" + newWidth + + " docW=" + docWidth); + if (newWidth <= docWidth) { + console.log("munger succeeded, elapsed time=" + (Date.now() - start)); + return; } } + + // OK, that wasn't enough. Try further munging all <td> to override text wrapping. + touched = addClassToElements(el.querySelectorAll("td"), null /* mungeAll */, "munged2", + actionLog); if (touched) { newWidth = el.scrollWidth; - console.log("ran div-width munger on el=" + el + " oldW=" + elWidth + " newW=" + newWidth + console.log("ran td munger2 on el=" + el + " oldW=" + elWidth + " newW=" + newWidth + " docW=" + docWidth); if (newWidth <= docWidth) { + console.log("munger succeeded, elapsed time=" + (Date.now() - start)); return; } } - // TODO: consider reversing changes that didn't help + // If the transformations shrank the width significantly enough, leave them in place. + // We figure that in those cases, the benefits outweight the risk of rendering artifacts. + // + // TODO: this is a risky transform that should not be attempted on sufficiently complex mail. + // (TBD how to measure that) + if ((elWidth - newWidth) / (elWidth - docWidth) > TRANSFORM_MINIMUM_EFFECTIVE_RATIO) { + console.log("transform(s) deemed effective enough. elapsed time=" + + (Date.now() - start)); + return; + } + + // reverse all changes if the width is STILL not narrow enough + // (except the width->maxWidth change, which is not particularly destructive) + for (i = 0, len = actionLog.length; i < len; i++) { + actionLog[i][0].classList.remove(actionLog[i][1]); + } + if (actionLog.length > 0) { + console.log("all mungers failed, changes reversed. elapsed time=" + (Date.now() - start)); + } +} + +function addClassToElements(nodes, conditionFn, classToAdd, actionLog) { + var i, len; + var node; + var added = false; + for (i = 0, len = nodes.length; i < len; i++) { + node = nodes[i]; + if (!conditionFn || conditionFn(node)) { + node.classList.add(classToAdd); + added = true; + actionLog.push([node, classToAdd]); + } + } + return added; +} + +function shouldMungeTable(table) { + return table.hasAttribute("width") || table.style.width; } function hideAllUnsafeImages() { |