commit bb7f1e27627bcd6766deacd1e8935743d83f2812
Author: Igor Oliveira <igor.oliveira(a)posteo.net>
Date: Sun Dec 10 18:16:59 2017 -0200
Bug 23104: Add a default line height compensation
Many fonts have issues with their vertical metrics. they
are used to influence the height of ascenders and depth
of descenders. Gecko uses it to calculate the line height
(font height + ascender + descender), however because of
that idiosyncratic behavior across multiple operating
systems, it can be used to identify the user's OS.
The solution proposed in the patch uses a default factor
to be multiplied with the font size, simulating the concept
of ascender and descender. This way all operating
systems will have the same line height only and only if the
frame is outside the chrome.
---
layout/generic/ReflowInput.cpp | 19 ++++++++---
layout/generic/test/mochitest.ini | 1 +
layout/generic/test/test_tor_bug23104.html | 51 ++++++++++++++++++++++++++++++
3 files changed, 66 insertions(+), 5 deletions(-)
diff --git a/layout/generic/ReflowInput.cpp b/layout/generic/ReflowInput.cpp
index 5b1f6d62043a..5da354f86558 100644
--- a/layout/generic/ReflowInput.cpp
+++ b/layout/generic/ReflowInput.cpp
@@ -30,6 +30,7 @@
#include <algorithm>
#include "mozilla/dom/HTMLInputElement.h"
#include "nsGridContainerFrame.h"
+#include "nsContentUtils.h"
using namespace mozilla;
using namespace mozilla::css;
@@ -2690,7 +2691,8 @@ void ReflowInput::CalculateBlockSideMargins(LayoutFrameType aFrameType) {
// For risk management, we use preference to control the behavior, and
// eNoExternalLeading is the old behavior.
-static nscoord GetNormalLineHeight(nsFontMetrics* aFontMetrics) {
+static nscoord GetNormalLineHeight(nsIContent* aContent,
+ nsFontMetrics* aFontMetrics) {
MOZ_ASSERT(nullptr != aFontMetrics, "no font metrics");
nscoord normalLineHeight;
@@ -2698,6 +2700,12 @@ static nscoord GetNormalLineHeight(nsFontMetrics* aFontMetrics) {
nscoord externalLeading = aFontMetrics->ExternalLeading();
nscoord internalLeading = aFontMetrics->InternalLeading();
nscoord emHeight = aFontMetrics->EmHeight();
+
+ if (nsContentUtils::ShouldResistFingerprinting() &&
+ !aContent->IsInChromeDocument()) {
+ return NSToCoordRound(emHeight * NORMAL_LINE_HEIGHT_FACTOR);
+ }
+
switch (GetNormalLineHeightCalcControl()) {
case eIncludeExternalLeading:
normalLineHeight = emHeight + internalLeading + externalLeading;
@@ -2715,7 +2723,8 @@ static nscoord GetNormalLineHeight(nsFontMetrics* aFontMetrics) {
return normalLineHeight;
}
-static inline nscoord ComputeLineHeight(ComputedStyle* aComputedStyle,
+static inline nscoord ComputeLineHeight(nsIContent* aContent,
+ ComputedStyle* aComputedStyle,
nsPresContext* aPresContext,
nscoord aBlockBSize,
float aFontSizeInflation) {
@@ -2743,7 +2752,7 @@ static inline nscoord ComputeLineHeight(ComputedStyle* aComputedStyle,
RefPtr<nsFontMetrics> fm = nsLayoutUtils::GetFontMetricsForComputedStyle(
aComputedStyle, aPresContext, aFontSizeInflation);
- return GetNormalLineHeight(fm);
+ return GetNormalLineHeight(aContent, fm);
}
nscoord ReflowInput::CalcLineHeight() const {
@@ -2765,7 +2774,7 @@ nscoord ReflowInput::CalcLineHeight(nsIContent* aContent,
float aFontSizeInflation) {
MOZ_ASSERT(aComputedStyle, "Must have a ComputedStyle");
- nscoord lineHeight = ComputeLineHeight(aComputedStyle, aPresContext,
+ nscoord lineHeight = ComputeLineHeight(aContent, aComputedStyle, aPresContext,
aBlockBSize, aFontSizeInflation);
NS_ASSERTION(lineHeight >= 0, "ComputeLineHeight screwed up");
@@ -2778,7 +2787,7 @@ nscoord ReflowInput::CalcLineHeight(nsIContent* aContent,
if (!lh.IsNormal()) {
RefPtr<nsFontMetrics> fm = nsLayoutUtils::GetFontMetricsForComputedStyle(
aComputedStyle, aPresContext, aFontSizeInflation);
- nscoord normal = GetNormalLineHeight(fm);
+ nscoord normal = GetNormalLineHeight(aContent, fm);
if (lineHeight < normal) {
lineHeight = normal;
}
diff --git a/layout/generic/test/mochitest.ini b/layout/generic/test/mochitest.ini
index f6678d8d8e4e..c1602bbbc6b1 100644
--- a/layout/generic/test/mochitest.ini
+++ b/layout/generic/test/mochitest.ini
@@ -161,3 +161,4 @@ skip-if = debug == true || tsan # the test is slow. tsan: bug 1612707
[test_reframe_for_lazy_load_image.html]
support-files =
file_reframe_for_lazy_load_image.html
+[test_tor_bug23104.html]
diff --git a/layout/generic/test/test_tor_bug23104.html b/layout/generic/test/test_tor_bug23104.html
new file mode 100644
index 000000000000..ae73a3446037
--- /dev/null
+++ b/layout/generic/test/test_tor_bug23104.html
@@ -0,0 +1,51 @@
+<!DOCTYPE HTML>
+<meta charset="UTF-8">
+<html>
+<head>
+ <title>Test for Tor Bug #23104: CSS line-height reveals the platform Tor browser is running</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="/tests/SimpleTest/SpawnTask.js"></script>
+ <style type="text/css">
+ span {
+ background-color: #000;
+ color: #fff;
+ font-size: 16.5px;
+ }
+ </style>
+</head>
+<body>
+<span id="test1">Test1</span>
+<span id="test2">كلمة</span>
+<span id="test3">ação</span>
+<script type="application/javascript;version=1.7">
+
+let setPref = function* (key, value) {
+ return new Promise(function(resolve, reject) {
+ SpecialPowers.pushPrefEnv({"set": [[key, value]]}, resolve);
+ });
+}
+
+function getStyle(el, styleprop) {
+ el = document.getElementById(el);
+ return document.defaultView.getComputedStyle(el, null).getPropertyValue(styleprop);
+}
+
+function validateElement(elementName, isFingerprintResistent) {
+ var fontSize = getStyle(elementName, 'font-size');
+ var lineHeight = getStyle(elementName, 'line-height');
+ var validationCb = isFingerprintResistent ? is : isnot;
+ validationCb(parseFloat(lineHeight), parseFloat(fontSize) * 1.2, 'Line Height validation');
+}
+
+add_task(function* () {
+ for (let resistFingerprintingValue of [true, false]) {
+ yield setPref("privacy.resistFingerprinting", resistFingerprintingValue);
+ for (let elementId of ['test1', 'test2', 'test3']) {
+ validateElement(elementId, resistFingerprintingValue);
+ }
+ }
+});
+
+</script>
+</body>
+</html>