Merge inbound to central, a=merge

MozReview-Commit-ID: 7EzhCCVVn7n
This commit is contained in:
Wes Kocher 2017-09-25 16:41:34 -07:00
Родитель 3a1e5b73d3 29bb494af7
Коммит 7bf1b49628
150 изменённых файлов: 3332 добавлений и 6909 удалений

Просмотреть файл

@ -32,9 +32,7 @@
#include "mozilla/StyleSheetInlines.h"
#include "mozilla/dom/Location.h"
#ifdef ENABLE_INTL_API
#include "unicode/uloc.h"
#endif
nsChromeRegistry* nsChromeRegistry::gChromeRegistry;
@ -638,7 +636,6 @@ nsChromeRegistry::MustLoadURLRemotely(nsIURI *aURI, bool *aResult)
bool
nsChromeRegistry::GetDirectionForLocale(const nsACString& aLocale)
{
#ifdef ENABLE_INTL_API
int pref = mozilla::Preferences::GetInt("intl.uidirection", -1);
if (pref >= 0) {
return (pref > 0);
@ -646,28 +643,6 @@ nsChromeRegistry::GetDirectionForLocale(const nsACString& aLocale)
nsAutoCString locale(aLocale);
SanitizeForBCP47(locale);
return uloc_isRightToLeft(locale.get());
#else
// first check the intl.uidirection.<locale> preference, and if that is not
// set, check the same preference but with just the first two characters of
// the locale. If that isn't set, default to left-to-right.
nsAutoCString prefString = NS_LITERAL_CSTRING("intl.uidirection.") + aLocale;
nsCOMPtr<nsIPrefBranch> prefBranch (do_GetService(NS_PREFSERVICE_CONTRACTID));
if (!prefBranch) {
return false;
}
nsCString dir;
prefBranch->GetCharPref(prefString.get(), getter_Copies(dir));
if (dir.IsEmpty()) {
int32_t hyphen = prefString.FindChar('-');
if (hyphen >= 1) {
nsAutoCString shortPref(Substring(prefString, 0, hyphen));
prefBranch->GetCharPref(shortPref.get(), getter_Copies(dir));
}
}
return dir.EqualsLiteral("rtl");
#endif
}
NS_IMETHODIMP_(bool)
@ -715,7 +690,6 @@ nsChromeRegistry::GetSingleton()
void
nsChromeRegistry::SanitizeForBCP47(nsACString& aLocale)
{
#ifdef ENABLE_INTL_API
// Currently, the only locale code we use that's not BCP47-conformant is
// "ja-JP-mac" on OS X, but let's try to be more general than just
// hard-coding that here.
@ -730,13 +704,4 @@ nsChromeRegistry::SanitizeForBCP47(nsACString& aLocale)
if (U_SUCCESS(err) && len > 0) {
aLocale.Assign(langTag, len);
}
#else
// This is only really needed for Intl API purposes, AFAIK,
// so probably won't be used in a non-ENABLE_INTL_API build.
// But let's fix up the single anomalous code we actually ship,
// just in case:
if (aLocale.EqualsLiteral("ja-JP-mac")) {
aLocale.AssignLiteral("ja-JP");
}
#endif
}

Просмотреть файл

@ -34,9 +34,6 @@ function performTest() {
// Make sure that the search box becomes focused when pressing ctrl+f - Bug 1211038
gEditor.focus();
synthesizeKeyFromKeyTag(gDebugger.document.getElementById("tokenSearchKey"));
let focusedEl = Services.focus.focusedElement;
focusedEl = focusedEl.ownerDocument.getBindingParent(focusedEl) || focusedEl;
is(focusedEl, gDebugger.document.getElementById("searchbox"), "Searchbox is focused");
setText(gSearchBox, "#html");

Просмотреть файл

@ -5,7 +5,7 @@ code, and optionally help with indentation.
# Upgrade
Currently used version is 5.29.0. To upgrade: download a new version of
Currently used version is 5.30.0. To upgrade: download a new version of
CodeMirror from the project's page [1] and replace all JavaScript and
CSS files inside the codemirror directory [2].

Просмотреть файл

@ -23,6 +23,7 @@
cm.state.closeBrackets = null;
}
if (val) {
ensureBound(getOption(val, "pairs"))
cm.state.closeBrackets = val;
cm.addKeyMap(keyMap);
}
@ -34,10 +35,14 @@
return defaults[name];
}
var bind = defaults.pairs + "`";
var keyMap = {Backspace: handleBackspace, Enter: handleEnter};
for (var i = 0; i < bind.length; i++)
keyMap["'" + bind.charAt(i) + "'"] = handler(bind.charAt(i));
function ensureBound(chars) {
for (var i = 0; i < chars.length; i++) {
var ch = chars.charAt(i), key = "'" + ch + "'"
if (!keyMap[key]) keyMap[key] = handler(ch)
}
}
ensureBound(defaults.pairs + "`")
function handler(ch) {
return function(cm) { return handleChar(cm, ch); };

Просмотреть файл

@ -302,7 +302,7 @@
setTimeout(function(){cm.focus();}, 20);
});
CodeMirror.signal(data, "select", completions[0], hints.firstChild);
CodeMirror.signal(data, "select", completions[this.selectedHint], hints.childNodes[this.selectedHint]);
return true;
}

Просмотреть файл

@ -132,6 +132,7 @@
var state = getSearchState(cm);
if (state.query) return findNext(cm, rev);
var q = cm.getSelection() || state.lastQuery;
if (q instanceof RegExp && q.source == "x^") q = null
if (persistent && cm.openDialog) {
var hiding = null
var searchNext = function(query, event) {

Просмотреть файл

@ -86,7 +86,7 @@
if (!array.length) return coverRange(cm, from, to);
var coverStart = array[0].find(), coverEnd = array[array.length - 1].find();
if (!coverStart || !coverEnd || to.line - from.line < CHUNK_SIZE ||
if (!coverStart || !coverEnd || to.line - from.line <= CHUNK_SIZE ||
cmp(from, coverEnd.to) >= 0 || cmp(to, coverStart.from) <= 0)
return reset(cm);

Просмотреть файл

@ -571,7 +571,7 @@
return {type: "part",
name: data.name,
offsetLines: from.line,
text: doc.getRange(from, Pos(endLine, 0))};
text: doc.getRange(from, Pos(endLine, end.line == endLine ? null : 0))};
}
// Generic utilities

Просмотреть файл

@ -520,13 +520,18 @@ var CodeMirror =
}
// Returns the value from the range [`from`; `to`] that satisfies
// `pred` and is closest to `from`. Assumes that at least `to` satisfies `pred`.
// `pred` and is closest to `from`. Assumes that at least `to`
// satisfies `pred`. Supports `from` being greater than `to`.
function findFirst(pred, from, to) {
// At any point we are certain `to` satisfies `pred`, don't know
// whether `from` does.
var dir = from > to ? -1 : 1
for (;;) {
if (Math.abs(from - to) <= 1) { return pred(from) ? from : to }
var mid = Math.floor((from + to) / 2)
if (from == to) { return from }
var midF = (from + to) / 2, mid = dir < 0 ? Math.ceil(midF) : Math.floor(midF)
if (mid == from) { return pred(mid) ? from : to }
if (pred(mid)) { to = mid }
else { from = mid }
else { from = mid + dir }
}
}
@ -1139,12 +1144,12 @@ var CodeMirror =
// BIDI HELPERS
function iterateBidiSections(order, from, to, f) {
if (!order) { return f(from, to, "ltr") }
if (!order) { return f(from, to, "ltr", 0) }
var found = false
for (var i = 0; i < order.length; ++i) {
var part = order[i]
if (part.from < to && part.to > from || from == to && part.to == from) {
f(Math.max(part.from, from), Math.min(part.to, to), part.level == 1 ? "rtl" : "ltr")
f(Math.max(part.from, from), Math.min(part.to, to), part.level == 1 ? "rtl" : "ltr", i)
found = true
}
}
@ -1347,112 +1352,6 @@ var CodeMirror =
return order
}
function moveCharLogically(line, ch, dir) {
var target = skipExtendingChars(line.text, ch + dir, dir)
return target < 0 || target > line.text.length ? null : target
}
function moveLogically(line, start, dir) {
var ch = moveCharLogically(line, start.ch, dir)
return ch == null ? null : new Pos(start.line, ch, dir < 0 ? "after" : "before")
}
function endOfLine(visually, cm, lineObj, lineNo, dir) {
if (visually) {
var order = getOrder(lineObj, cm.doc.direction)
if (order) {
var part = dir < 0 ? lst(order) : order[0]
var moveInStorageOrder = (dir < 0) == (part.level == 1)
var sticky = moveInStorageOrder ? "after" : "before"
var ch
// With a wrapped rtl chunk (possibly spanning multiple bidi parts),
// it could be that the last bidi part is not on the last visual line,
// since visual lines contain content order-consecutive chunks.
// Thus, in rtl, we are looking for the first (content-order) character
// in the rtl chunk that is on the last line (that is, the same line
// as the last (content-order) character).
if (part.level > 0) {
var prep = prepareMeasureForLine(cm, lineObj)
ch = dir < 0 ? lineObj.text.length - 1 : 0
var targetTop = measureCharPrepared(cm, prep, ch).top
ch = findFirst(function (ch) { return measureCharPrepared(cm, prep, ch).top == targetTop; }, (dir < 0) == (part.level == 1) ? part.from : part.to - 1, ch)
if (sticky == "before") { ch = moveCharLogically(lineObj, ch, 1) }
} else { ch = dir < 0 ? part.to : part.from }
return new Pos(lineNo, ch, sticky)
}
}
return new Pos(lineNo, dir < 0 ? lineObj.text.length : 0, dir < 0 ? "before" : "after")
}
function moveVisually(cm, line, start, dir) {
var bidi = getOrder(line, cm.doc.direction)
if (!bidi) { return moveLogically(line, start, dir) }
if (start.ch >= line.text.length) {
start.ch = line.text.length
start.sticky = "before"
} else if (start.ch <= 0) {
start.ch = 0
start.sticky = "after"
}
var partPos = getBidiPartAt(bidi, start.ch, start.sticky), part = bidi[partPos]
if (cm.doc.direction == "ltr" && part.level % 2 == 0 && (dir > 0 ? part.to > start.ch : part.from < start.ch)) {
// Case 1: We move within an ltr part in an ltr editor. Even with wrapped lines,
// nothing interesting happens.
return moveLogically(line, start, dir)
}
var mv = function (pos, dir) { return moveCharLogically(line, pos instanceof Pos ? pos.ch : pos, dir); }
var prep
var getWrappedLineExtent = function (ch) {
if (!cm.options.lineWrapping) { return {begin: 0, end: line.text.length} }
prep = prep || prepareMeasureForLine(cm, line)
return wrappedLineExtentChar(cm, line, prep, ch)
}
var wrappedLineExtent = getWrappedLineExtent(start.sticky == "before" ? mv(start, -1) : start.ch)
if (cm.doc.direction == "rtl" || part.level == 1) {
var moveInStorageOrder = (part.level == 1) == (dir < 0)
var ch = mv(start, moveInStorageOrder ? 1 : -1)
if (ch != null && (!moveInStorageOrder ? ch >= part.from && ch >= wrappedLineExtent.begin : ch <= part.to && ch <= wrappedLineExtent.end)) {
// Case 2: We move within an rtl part or in an rtl editor on the same visual line
var sticky = moveInStorageOrder ? "before" : "after"
return new Pos(start.line, ch, sticky)
}
}
// Case 3: Could not move within this bidi part in this visual line, so leave
// the current bidi part
var searchInVisualLine = function (partPos, dir, wrappedLineExtent) {
var getRes = function (ch, moveInStorageOrder) { return moveInStorageOrder
? new Pos(start.line, mv(ch, 1), "before")
: new Pos(start.line, ch, "after"); }
for (; partPos >= 0 && partPos < bidi.length; partPos += dir) {
var part = bidi[partPos]
var moveInStorageOrder = (dir > 0) == (part.level != 1)
var ch = moveInStorageOrder ? wrappedLineExtent.begin : mv(wrappedLineExtent.end, -1)
if (part.from <= ch && ch < part.to) { return getRes(ch, moveInStorageOrder) }
ch = moveInStorageOrder ? part.from : mv(part.to, -1)
if (wrappedLineExtent.begin <= ch && ch < wrappedLineExtent.end) { return getRes(ch, moveInStorageOrder) }
}
}
// Case 3a: Look for other bidi parts on the same visual line
var res = searchInVisualLine(partPos + dir, dir, wrappedLineExtent)
if (res) { return res }
// Case 3b: Look for other bidi parts on the next visual line
var nextCh = dir > 0 ? wrappedLineExtent.end : mv(wrappedLineExtent.begin, -1)
if (nextCh != null && !(dir > 0 && nextCh == line.text.length)) {
res = searchInVisualLine(dir > 0 ? 0 : bidi.length - 1, dir, getWrappedLineExtent(nextCh))
if (res) { return res }
}
// Case 4: Nowhere to move
return null
}
// EVENT HANDLING
// Lightweight event framework. on/off also work on DOM nodes,
@ -2961,15 +2860,22 @@ var CodeMirror =
return window.pageYOffset || (document.documentElement || document.body).scrollTop
}
function widgetTopHeight(lineObj) {
var height = 0
if (lineObj.widgets) { for (var i = 0; i < lineObj.widgets.length; ++i) { if (lineObj.widgets[i].above)
{ height += widgetHeight(lineObj.widgets[i]) } } }
return height
}
// Converts a {top, bottom, left, right} box from line-local
// coordinates into another coordinate system. Context may be one of
// "line", "div" (display.lineDiv), "local"./null (editor), "window",
// or "page".
function intoCoordSystem(cm, lineObj, rect, context, includeWidgets) {
if (!includeWidgets && lineObj.widgets) { for (var i = 0; i < lineObj.widgets.length; ++i) { if (lineObj.widgets[i].above) {
var size = widgetHeight(lineObj.widgets[i])
rect.top += size; rect.bottom += size
} } }
if (!includeWidgets) {
var height = widgetTopHeight(lineObj)
rect.top += height; rect.bottom += height
}
if (context == "line") { return rect }
if (!context) { context = "local" }
var yOff = heightAtLine(lineObj)
@ -3044,7 +2950,7 @@ var CodeMirror =
if (!order) { return get(sticky == "before" ? ch - 1 : ch, sticky == "before") }
function getBidi(ch, partPos, invert) {
var part = order[partPos], right = (part.level % 2) != 0
var part = order[partPos], right = part.level == 1
return get(invert ? ch - 1 : ch, right != invert)
}
var partPos = getBidiPartAt(order, ch, sticky)
@ -3102,77 +3008,146 @@ var CodeMirror =
}
function wrappedLineExtent(cm, lineObj, preparedMeasure, y) {
var measure = function (ch) { return intoCoordSystem(cm, lineObj, measureCharPrepared(cm, preparedMeasure, ch), "line"); }
y -= widgetTopHeight(lineObj)
var end = lineObj.text.length
var begin = findFirst(function (ch) { return measure(ch - 1).bottom <= y; }, end, 0)
end = findFirst(function (ch) { return measure(ch).top > y; }, begin, end)
var begin = findFirst(function (ch) { return measureCharPrepared(cm, preparedMeasure, ch - 1).bottom <= y; }, end, 0)
end = findFirst(function (ch) { return measureCharPrepared(cm, preparedMeasure, ch).top > y; }, begin, end)
return {begin: begin, end: end}
}
function wrappedLineExtentChar(cm, lineObj, preparedMeasure, target) {
if (!preparedMeasure) { preparedMeasure = prepareMeasureForLine(cm, lineObj) }
var targetTop = intoCoordSystem(cm, lineObj, measureCharPrepared(cm, preparedMeasure, target), "line").top
return wrappedLineExtent(cm, lineObj, preparedMeasure, targetTop)
}
// Returns true if the given side of a box is after the given
// coordinates, in top-to-bottom, left-to-right order.
function boxIsAfter(box, x, y, left) {
return box.bottom <= y ? false : box.top > y ? true : (left ? box.left : box.right) > x
}
function coordsCharInner(cm, lineObj, lineNo, x, y) {
// Move y into line-local coordinate space
y -= heightAtLine(lineObj)
var begin = 0, end = lineObj.text.length
var preparedMeasure = prepareMeasureForLine(cm, lineObj)
var pos
// When directly calling `measureCharPrepared`, we have to adjust
// for the widgets at this line.
var widgetHeight = widgetTopHeight(lineObj)
var begin = 0, end = lineObj.text.length, ltr = true
var order = getOrder(lineObj, cm.doc.direction)
// If the line isn't plain left-to-right text, first figure out
// which bidi section the coordinates fall into.
if (order) {
if (cm.options.lineWrapping) {
;var assign;
((assign = wrappedLineExtent(cm, lineObj, preparedMeasure, y), begin = assign.begin, end = assign.end, assign))
}
pos = new Pos(lineNo, Math.floor(begin + (end - begin) / 2))
var beginLeft = cursorCoords(cm, pos, "line", lineObj, preparedMeasure).left
var dir = beginLeft < x ? 1 : -1
var prevDiff, diff = beginLeft - x, prevPos
var steps = Math.ceil((end - begin) / 4)
outer: do {
prevDiff = diff
prevPos = pos
var i = 0
for (; i < steps; ++i) {
var prevPos$1 = pos
pos = moveVisually(cm, lineObj, pos, dir)
if (pos == null || pos.ch < begin || end <= (pos.sticky == "before" ? pos.ch - 1 : pos.ch)) {
pos = prevPos$1
break outer
}
}
diff = cursorCoords(cm, pos, "line", lineObj, preparedMeasure).left - x
if (steps > 1) {
var diff_change_per_step = Math.abs(diff - prevDiff) / steps
steps = Math.min(steps, Math.ceil(Math.abs(diff) / diff_change_per_step))
dir = diff < 0 ? 1 : -1
}
} while (diff != 0 && (steps > 1 || ((dir < 0) != (diff < 0) && (Math.abs(diff) <= Math.abs(prevDiff)))))
if (Math.abs(diff) > Math.abs(prevDiff)) {
if ((diff < 0) == (prevDiff < 0)) { throw new Error("Broke out of infinite loop in coordsCharInner") }
pos = prevPos
}
} else {
var ch = findFirst(function (ch) {
var box = intoCoordSystem(cm, lineObj, measureCharPrepared(cm, preparedMeasure, ch), "line")
if (box.top > y) {
// For the cursor stickiness
end = Math.min(ch, end)
return true
}
else if (box.bottom <= y) { return false }
else if (box.left > x) { return true }
else if (box.right < x) { return false }
else { return (x - box.left < box.right - x) }
}, begin, end)
ch = skipExtendingChars(lineObj.text, ch, 1)
pos = new Pos(lineNo, ch, ch == end ? "before" : "after")
var part = (cm.options.lineWrapping ? coordsBidiPartWrapped : coordsBidiPart)
(cm, lineObj, lineNo, preparedMeasure, order, x, y)
ltr = part.level != 1
// The awkward -1 offsets are needed because findFirst (called
// on these below) will treat its first bound as inclusive,
// second as exclusive, but we want to actually address the
// characters in the part's range
begin = ltr ? part.from : part.to - 1
end = ltr ? part.to : part.from - 1
}
var coords = cursorCoords(cm, pos, "line", lineObj, preparedMeasure)
if (y < coords.top || coords.bottom < y) { pos.outside = true }
pos.xRel = x < coords.left ? -1 : (x > coords.right ? 1 : 0)
return pos
// A binary search to find the first character whose bounding box
// starts after the coordinates. If we run across any whose box wrap
// the coordinates, store that.
var chAround = null, boxAround = null
var ch = findFirst(function (ch) {
var box = measureCharPrepared(cm, preparedMeasure, ch)
box.top += widgetHeight; box.bottom += widgetHeight
if (!boxIsAfter(box, x, y, false)) { return false }
if (box.top <= y && box.left <= x) {
chAround = ch
boxAround = box
}
return true
}, begin, end)
var baseX, sticky, outside = false
// If a box around the coordinates was found, use that
if (boxAround) {
// Distinguish coordinates nearer to the left or right side of the box
var atLeft = x - boxAround.left < boxAround.right - x, atStart = atLeft == ltr
ch = chAround + (atStart ? 0 : 1)
sticky = atStart ? "after" : "before"
baseX = atLeft ? boxAround.left : boxAround.right
} else {
// (Adjust for extended bound, if necessary.)
if (!ltr && (ch == end || ch == begin)) { ch++ }
// To determine which side to associate with, get the box to the
// left of the character and compare it's vertical position to the
// coordinates
sticky = ch == 0 ? "after" : ch == lineObj.text.length ? "before" :
(measureCharPrepared(cm, preparedMeasure, ch - (ltr ? 1 : 0)).bottom + widgetHeight <= y) == ltr ?
"after" : "before"
// Now get accurate coordinates for this place, in order to get a
// base X position
var coords = cursorCoords(cm, Pos(lineNo, ch, sticky), "line", lineObj, preparedMeasure)
baseX = coords.left
outside = y < coords.top || y >= coords.bottom
}
ch = skipExtendingChars(lineObj.text, ch, 1)
return PosWithInfo(lineNo, ch, sticky, outside, x - baseX)
}
function coordsBidiPart(cm, lineObj, lineNo, preparedMeasure, order, x, y) {
// Bidi parts are sorted left-to-right, and in a non-line-wrapping
// situation, we can take this ordering to correspond to the visual
// ordering. This finds the first part whose end is after the given
// coordinates.
var index = findFirst(function (i) {
var part = order[i], ltr = part.level != 1
return boxIsAfter(cursorCoords(cm, Pos(lineNo, ltr ? part.to : part.from, ltr ? "before" : "after"),
"line", lineObj, preparedMeasure), x, y, true)
}, 0, order.length - 1)
var part = order[index]
// If this isn't the first part, the part's start is also after
// the coordinates, and the coordinates aren't on the same line as
// that start, move one part back.
if (index > 0) {
var ltr = part.level != 1
var start = cursorCoords(cm, Pos(lineNo, ltr ? part.from : part.to, ltr ? "after" : "before"),
"line", lineObj, preparedMeasure)
if (boxIsAfter(start, x, y, true) && start.top > y)
{ part = order[index - 1] }
}
return part
}
function coordsBidiPartWrapped(cm, lineObj, _lineNo, preparedMeasure, order, x, y) {
// In a wrapped line, rtl text on wrapping boundaries can do things
// that don't correspond to the ordering in our `order` array at
// all, so a binary search doesn't work, and we want to return a
// part that only spans one line so that the binary search in
// coordsCharInner is safe. As such, we first find the extent of the
// wrapped line, and then do a flat search in which we discard any
// spans that aren't on the line.
var ref = wrappedLineExtent(cm, lineObj, preparedMeasure, y);
var begin = ref.begin;
var end = ref.end;
var part = null, closestDist = null
for (var i = 0; i < order.length; i++) {
var p = order[i]
if (p.from >= end || p.to <= begin) { continue }
var ltr = p.level != 1
var endX = measureCharPrepared(cm, preparedMeasure, ltr ? Math.min(end, p.to) - 1 : Math.max(begin, p.from)).right
// Weigh against spans ending before this, so that they are only
// picked if nothing ends after
var dist = endX < x ? x - endX + 1e9 : endX - x
if (!part || closestDist > dist) {
part = p
closestDist = dist
}
}
if (!part) { part = order[order.length - 1] }
// Clip the part to the wrapped line.
if (part.from < begin) { part = {from: begin, to: part.to, level: part.level} }
if (part.to > end) { part = {from: part.from, to: end, level: part.level} }
return part
}
var measureText
@ -3298,12 +3273,14 @@ var CodeMirror =
}
function prepareSelection(cm, primary) {
if ( primary === void 0 ) primary = true;
var doc = cm.doc, result = {}
var curFragment = result.cursors = document.createDocumentFragment()
var selFragment = result.selection = document.createDocumentFragment()
for (var i = 0; i < doc.sel.ranges.length; i++) {
if (primary === false && i == doc.sel.primIndex) { continue }
if (!primary && i == doc.sel.primIndex) { continue }
var range = doc.sel.ranges[i]
if (range.from().line >= cm.display.viewTo || range.to().line < cm.display.viewFrom) { continue }
var collapsed = range.empty()
@ -3334,6 +3311,8 @@ var CodeMirror =
}
}
function cmpCoords(a, b) { return a.top - b.top || a.left - b.left }
// Draws the given range as a highlighted selection
function drawSelectionRange(cm, range, output) {
var display = cm.display, doc = cm.doc
@ -3356,30 +3335,48 @@ var CodeMirror =
return charCoords(cm, Pos(line, ch), "div", lineObj, bias)
}
iterateBidiSections(getOrder(lineObj, doc.direction), fromArg || 0, toArg == null ? lineLen : toArg, function (from, to, dir) {
var leftPos = coords(from, "left"), rightPos, left, right
if (from == to) {
rightPos = leftPos
left = right = leftPos.left
} else {
rightPos = coords(to - 1, "right")
if (dir == "rtl") { var tmp = leftPos; leftPos = rightPos; rightPos = tmp }
left = leftPos.left
right = rightPos.right
var order = getOrder(lineObj, doc.direction)
iterateBidiSections(order, fromArg || 0, toArg == null ? lineLen : toArg, function (from, to, dir, i) {
var fromPos = coords(from, dir == "ltr" ? "left" : "right")
var toPos = coords(to - 1, dir == "ltr" ? "right" : "left")
if (dir == "ltr") {
var fromLeft = fromArg == null && from == 0 ? leftSide : fromPos.left
var toRight = toArg == null && to == lineLen ? rightSide : toPos.right
if (toPos.top - fromPos.top <= 3) { // Single line
add(fromLeft, toPos.top, toRight - fromLeft, toPos.bottom)
} else { // Multiple lines
add(fromLeft, fromPos.top, null, fromPos.bottom)
if (fromPos.bottom < toPos.top) { add(leftSide, fromPos.bottom, null, toPos.top) }
add(leftSide, toPos.top, toPos.right, toPos.bottom)
}
} else if (from < to) { // RTL
var fromRight = fromArg == null && from == 0 ? rightSide : fromPos.right
var toLeft = toArg == null && to == lineLen ? leftSide : toPos.left
if (toPos.top - fromPos.top <= 3) { // Single line
add(toLeft, toPos.top, fromRight - toLeft, toPos.bottom)
} else { // Multiple lines
var topLeft = leftSide
if (i) {
var topEnd = wrappedLineExtentChar(cm, lineObj, null, from).end
// The coordinates returned for an RTL wrapped space tend to
// be complete bogus, so try to skip that here.
topLeft = coords(topEnd - (/\s/.test(lineObj.text.charAt(topEnd - 1)) ? 2 : 1), "left").left
}
add(topLeft, fromPos.top, fromRight - topLeft, fromPos.bottom)
if (fromPos.bottom < toPos.top) { add(leftSide, fromPos.bottom, null, toPos.top) }
var botWidth = null
if (i < order.length - 1 || true) {
var botStart = wrappedLineExtentChar(cm, lineObj, null, to).begin
botWidth = coords(botStart, "right").right - toLeft
}
add(toLeft, toPos.top, botWidth, toPos.bottom)
}
}
if (fromArg == null && from == 0) { left = leftSide }
if (rightPos.top - leftPos.top > 3) { // Different lines, draw top part
add(left, leftPos.top, null, leftPos.bottom)
left = leftSide
if (leftPos.bottom < rightPos.top) { add(left, leftPos.bottom, null, rightPos.top) }
}
if (toArg == null && to == lineLen) { right = rightSide }
if (!start || leftPos.top < start.top || leftPos.top == start.top && leftPos.left < start.left)
{ start = leftPos }
if (!end || rightPos.bottom > end.bottom || rightPos.bottom == end.bottom && rightPos.right > end.right)
{ end = rightPos }
if (left < leftSide + 1) { left = leftSide }
add(left, rightPos.top, right - left, rightPos.bottom)
if (!start || cmpCoords(fromPos, start) < 0) { start = fromPos }
if (cmpCoords(toPos, start) < 0) { start = toPos }
if (!end || cmpCoords(fromPos, end) < 0) { end = fromPos }
if (cmpCoords(toPos, end) < 0) { end = toPos }
})
return {start: start, end: end}
}
@ -4009,7 +4006,7 @@ var CodeMirror =
}
if (op.updatedDisplay || op.selectionChanged)
{ op.preparedSelection = display.input.prepareSelection(op.focus) }
{ op.preparedSelection = display.input.prepareSelection() }
}
function endOperation_W2(op) {
@ -4022,7 +4019,7 @@ var CodeMirror =
cm.display.maxLineChanged = false
}
var takeFocus = op.focus && op.focus == activeElt() && (!document.hasFocus || document.hasFocus())
var takeFocus = op.focus && op.focus == activeElt()
if (op.preparedSelection)
{ cm.display.input.showSelection(op.preparedSelection, takeFocus) }
if (op.updatedDisplay || op.startHeight != cm.doc.height)
@ -5611,7 +5608,8 @@ var CodeMirror =
function replaceRange(doc, code, from, to, origin) {
if (!to) { to = from }
if (cmp(to, from) < 0) { var tmp = to; to = from; from = tmp }
if (cmp(to, from) < 0) { var assign;
(assign = [to, from], from = assign[0], to = assign[1], assign) }
if (typeof code == "string") { code = doc.splitLines(code) }
makeChange(doc, {from: from, to: to, text: code, origin: origin})
}
@ -6973,6 +6971,112 @@ var CodeMirror =
})
}
function moveCharLogically(line, ch, dir) {
var target = skipExtendingChars(line.text, ch + dir, dir)
return target < 0 || target > line.text.length ? null : target
}
function moveLogically(line, start, dir) {
var ch = moveCharLogically(line, start.ch, dir)
return ch == null ? null : new Pos(start.line, ch, dir < 0 ? "after" : "before")
}
function endOfLine(visually, cm, lineObj, lineNo, dir) {
if (visually) {
var order = getOrder(lineObj, cm.doc.direction)
if (order) {
var part = dir < 0 ? lst(order) : order[0]
var moveInStorageOrder = (dir < 0) == (part.level == 1)
var sticky = moveInStorageOrder ? "after" : "before"
var ch
// With a wrapped rtl chunk (possibly spanning multiple bidi parts),
// it could be that the last bidi part is not on the last visual line,
// since visual lines contain content order-consecutive chunks.
// Thus, in rtl, we are looking for the first (content-order) character
// in the rtl chunk that is on the last line (that is, the same line
// as the last (content-order) character).
if (part.level > 0) {
var prep = prepareMeasureForLine(cm, lineObj)
ch = dir < 0 ? lineObj.text.length - 1 : 0
var targetTop = measureCharPrepared(cm, prep, ch).top
ch = findFirst(function (ch) { return measureCharPrepared(cm, prep, ch).top == targetTop; }, (dir < 0) == (part.level == 1) ? part.from : part.to - 1, ch)
if (sticky == "before") { ch = moveCharLogically(lineObj, ch, 1) }
} else { ch = dir < 0 ? part.to : part.from }
return new Pos(lineNo, ch, sticky)
}
}
return new Pos(lineNo, dir < 0 ? lineObj.text.length : 0, dir < 0 ? "before" : "after")
}
function moveVisually(cm, line, start, dir) {
var bidi = getOrder(line, cm.doc.direction)
if (!bidi) { return moveLogically(line, start, dir) }
if (start.ch >= line.text.length) {
start.ch = line.text.length
start.sticky = "before"
} else if (start.ch <= 0) {
start.ch = 0
start.sticky = "after"
}
var partPos = getBidiPartAt(bidi, start.ch, start.sticky), part = bidi[partPos]
if (cm.doc.direction == "ltr" && part.level % 2 == 0 && (dir > 0 ? part.to > start.ch : part.from < start.ch)) {
// Case 1: We move within an ltr part in an ltr editor. Even with wrapped lines,
// nothing interesting happens.
return moveLogically(line, start, dir)
}
var mv = function (pos, dir) { return moveCharLogically(line, pos instanceof Pos ? pos.ch : pos, dir); }
var prep
var getWrappedLineExtent = function (ch) {
if (!cm.options.lineWrapping) { return {begin: 0, end: line.text.length} }
prep = prep || prepareMeasureForLine(cm, line)
return wrappedLineExtentChar(cm, line, prep, ch)
}
var wrappedLineExtent = getWrappedLineExtent(start.sticky == "before" ? mv(start, -1) : start.ch)
if (cm.doc.direction == "rtl" || part.level == 1) {
var moveInStorageOrder = (part.level == 1) == (dir < 0)
var ch = mv(start, moveInStorageOrder ? 1 : -1)
if (ch != null && (!moveInStorageOrder ? ch >= part.from && ch >= wrappedLineExtent.begin : ch <= part.to && ch <= wrappedLineExtent.end)) {
// Case 2: We move within an rtl part or in an rtl editor on the same visual line
var sticky = moveInStorageOrder ? "before" : "after"
return new Pos(start.line, ch, sticky)
}
}
// Case 3: Could not move within this bidi part in this visual line, so leave
// the current bidi part
var searchInVisualLine = function (partPos, dir, wrappedLineExtent) {
var getRes = function (ch, moveInStorageOrder) { return moveInStorageOrder
? new Pos(start.line, mv(ch, 1), "before")
: new Pos(start.line, ch, "after"); }
for (; partPos >= 0 && partPos < bidi.length; partPos += dir) {
var part = bidi[partPos]
var moveInStorageOrder = (dir > 0) == (part.level != 1)
var ch = moveInStorageOrder ? wrappedLineExtent.begin : mv(wrappedLineExtent.end, -1)
if (part.from <= ch && ch < part.to) { return getRes(ch, moveInStorageOrder) }
ch = moveInStorageOrder ? part.from : mv(part.to, -1)
if (wrappedLineExtent.begin <= ch && ch < wrappedLineExtent.end) { return getRes(ch, moveInStorageOrder) }
}
}
// Case 3a: Look for other bidi parts on the same visual line
var res = searchInVisualLine(partPos + dir, dir, wrappedLineExtent)
if (res) { return res }
// Case 3b: Look for other bidi parts on the next visual line
var nextCh = dir > 0 ? wrappedLineExtent.end : mv(wrappedLineExtent.begin, -1)
if (nextCh != null && !(dir > 0 && nextCh == line.text.length)) {
res = searchInVisualLine(dir > 0 ? 0 : bidi.length - 1, dir, getWrappedLineExtent(nextCh))
if (res) { return res }
}
// Case 4: Nowhere to move
return null
}
// Commands are parameter-less actions that can be performed on an
// editor, mostly used for keybindings.
var commands = {
@ -7534,7 +7638,7 @@ var CodeMirror =
anchor = maxPos(oldRange.to(), range.head)
}
var ranges$1 = startSel.ranges.slice(0)
ranges$1[ourIndex] = new Range(clipPos(doc, anchor), head)
ranges$1[ourIndex] = bidiSimplify(cm, new Range(clipPos(doc, anchor), head))
setSelection(doc, normalizeSelection(ranges$1, ourIndex), sel_mouse)
}
}
@ -7586,13 +7690,52 @@ var CodeMirror =
on(document, "mouseup", up)
}
// Used when mouse-selecting to adjust the anchor to the proper side
// of a bidi jump depending on the visual position of the head.
function bidiSimplify(cm, range) {
var anchor = range.anchor;
var head = range.head;
var anchorLine = getLine(cm.doc, anchor.line)
if (cmp(anchor, head) == 0 && anchor.sticky == head.sticky) { return range }
var order = getOrder(anchorLine)
if (!order) { return range }
var index = getBidiPartAt(order, anchor.ch, anchor.sticky), part = order[index]
if (part.from != anchor.ch && part.to != anchor.ch) { return range }
var boundary = index + ((part.from == anchor.ch) == (part.level != 1) ? 0 : 1)
if (boundary == 0 || boundary == order.length) { return range }
// Compute the relative visual position of the head compared to the
// anchor (<0 is to the left, >0 to the right)
var leftSide
if (head.line != anchor.line) {
leftSide = (head.line - anchor.line) * (cm.doc.direction == "ltr" ? 1 : -1) > 0
} else {
var headIndex = getBidiPartAt(order, head.ch, head.sticky)
var dir = headIndex - index || (head.ch - anchor.ch) * (part.level == 1 ? -1 : 1)
if (headIndex == boundary - 1 || headIndex == boundary)
{ leftSide = dir < 0 }
else
{ leftSide = dir > 0 }
}
var usePart = order[boundary + (leftSide ? -1 : 0)]
var from = leftSide == (usePart.level == 1)
var ch = from ? usePart.from : usePart.to, sticky = from ? "after" : "before"
return anchor.ch == ch && anchor.sticky == sticky ? range : new Range(new Pos(anchor.line, ch, sticky), head)
}
// Determines whether an event happened in the gutter, and fires the
// handlers for the corresponding event.
function gutterEvent(cm, e, type, prevent) {
var mX, mY
try { mX = e.clientX; mY = e.clientY }
catch(e) { return false }
if (e.touches) {
mX = e.touches[0].clientX
mY = e.touches[0].clientY
} else {
try { mX = e.clientX; mY = e.clientY }
catch(e) { return false }
}
if (mX >= Math.floor(cm.display.gutters.getBoundingClientRect().right)) { return false }
if (prevent) { e_preventDefault(e) }
@ -7930,7 +8073,7 @@ var CodeMirror =
return dx * dx + dy * dy > 20 * 20
}
on(d.scroller, "touchstart", function (e) {
if (!signalDOMEvent(cm, e) && !isMouseLikeTouchEvent(e)) {
if (!signalDOMEvent(cm, e) && !isMouseLikeTouchEvent(e) && !clickInGutter(cm, e)) {
d.input.ensurePolled()
clearTimeout(touchFinished)
var now = +new Date
@ -9714,7 +9857,7 @@ var CodeMirror =
addLegacyProps(CodeMirror)
CodeMirror.version = "5.29.0"
CodeMirror.version = "5.30.0"
return CodeMirror;
@ -10153,6 +10296,7 @@ var CodeMirror =
var state = getSearchState(cm);
if (state.query) return findNext(cm, rev);
var q = cm.getSelection() || state.lastQuery;
if (q instanceof RegExp && q.source == "x^") q = null
if (persistent && cm.openDialog) {
var hiding = null
var searchNext = function(query, event) {
@ -10462,6 +10606,7 @@ var CodeMirror =
cm.state.closeBrackets = null;
}
if (val) {
ensureBound(getOption(val, "pairs"))
cm.state.closeBrackets = val;
cm.addKeyMap(keyMap);
}
@ -10473,10 +10618,14 @@ var CodeMirror =
return defaults[name];
}
var bind = defaults.pairs + "`";
var keyMap = {Backspace: handleBackspace, Enter: handleEnter};
for (var i = 0; i < bind.length; i++)
keyMap["'" + bind.charAt(i) + "'"] = handler(bind.charAt(i));
function ensureBound(chars) {
for (var i = 0; i < chars.length; i++) {
var ch = chars.charAt(i), key = "'" + ch + "'"
if (!keyMap[key]) keyMap[key] = handler(ch)
}
}
ensureBound(defaults.pairs + "`")
function handler(ch) {
return function(cm) { return handleChar(cm, ch); };
@ -10894,7 +11043,7 @@ var CodeMirror =
var jsKeywords = {
"if": kw("if"), "while": A, "with": A, "else": B, "do": B, "try": B, "finally": B,
"return": C, "break": C, "continue": C, "new": kw("new"), "delete": C, "throw": C, "debugger": C,
"return": C, "break": C, "continue": C, "new": kw("new"), "delete": C, "void": C, "throw": C, "debugger": C,
"var": kw("var"), "const": kw("var"), "let": kw("var"),
"function": kw("function"), "catch": kw("catch"),
"for": kw("for"), "switch": kw("switch"), "case": kw("case"), "default": kw("default"),
@ -11264,7 +11413,7 @@ var CodeMirror =
function expressionInner(type, noComma) {
if (cx.state.fatArrowAt == cx.stream.start) {
var body = noComma ? arrowBodyNoComma : arrowBody;
if (type == "(") return cont(pushcontext, pushlex(")"), commasep(pattern, ")"), poplex, expect("=>"), body, popcontext);
if (type == "(") return cont(pushcontext, pushlex(")"), commasep(funarg, ")"), poplex, expect("=>"), body, popcontext);
else if (type == "variable") return pass(pushcontext, pattern, expect("=>"), body, popcontext);
}
@ -11309,6 +11458,11 @@ var CodeMirror =
if (type == ".") return cont(property, me);
if (type == "[") return cont(pushlex("]"), maybeexpression, expect("]"), poplex, me);
if (isTS && value == "as") { cx.marked = "keyword"; return cont(typeexpr, me) }
if (type == "regexp") {
cx.state.lastType = cx.marked = "operator"
cx.stream.backUp(cx.stream.pos - cx.stream.start - 1)
return cont(expr)
}
}
function quasi(type, value) {
if (type != "quasi") return pass();
@ -11357,6 +11511,9 @@ var CodeMirror =
} else if (type == "variable" || cx.style == "keyword") {
cx.marked = "property";
if (value == "get" || value == "set") return cont(getterSetter);
var m // Work around fat-arrow-detection complication for detecting typescript typed arrow params
if (isTS && cx.state.fatArrowAt == cx.stream.start && (m = cx.stream.match(/^\s*:\s*/, false)))
cx.state.fatArrowAt = cx.stream.pos + m[0].length
return cont(afterprop);
} else if (type == "number" || type == "string") {
cx.marked = jsonldMode ? "property" : (cx.style + " property");
@ -11514,7 +11671,8 @@ var CodeMirror =
if (type == "(") return cont(pushcontext, pushlex(")"), commasep(funarg, ")"), poplex, maybetype, statement, popcontext);
if (isTS && value == "<") return cont(pushlex(">"), commasep(typeexpr, ">"), poplex, functiondef)
}
function funarg(type) {
function funarg(type, value) {
if (value == "@") cont(expression, funarg)
if (type == "spread" || type == "modifier") return cont(funarg);
return pass(pattern, maybetype, maybeAssign);
}
@ -11540,7 +11698,7 @@ var CodeMirror =
cx.marked = "keyword";
return cont(classBody);
}
if (type == "variable") {
if (type == "variable" || cx.style == "keyword") {
cx.marked = "property";
return cont(isTS ? classfield : functiondef, classBody);
}
@ -11602,7 +11760,7 @@ var CodeMirror =
function expressionAllowed(stream, state, backUp) {
return state.tokenize == tokenBase &&
/^(?:operator|sof|keyword c|case|new|export|default|[\[{}\(,;:]|=>)$/.test(state.lastType) ||
/^(?:operator|sof|keyword [bc]|case|new|export|default|spread|[\[{}\(,;:]|=>)$/.test(state.lastType) ||
(state.lastType == "quasi" && /\{\s*$/.test(stream.string.slice(0, stream.pos - (backUp || 0))))
}

Просмотреть файл

@ -278,13 +278,18 @@ function skipExtendingChars(str, pos, dir) {
}
// Returns the value from the range [`from`; `to`] that satisfies
// `pred` and is closest to `from`. Assumes that at least `to` satisfies `pred`.
// `pred` and is closest to `from`. Assumes that at least `to`
// satisfies `pred`. Supports `from` being greater than `to`.
function findFirst(pred, from, to) {
// At any point we are certain `to` satisfies `pred`, don't know
// whether `from` does.
var dir = from > to ? -1 : 1
for (;;) {
if (Math.abs(from - to) <= 1) { return pred(from) ? from : to }
var mid = Math.floor((from + to) / 2)
if (from == to) { return from }
var midF = (from + to) / 2, mid = dir < 0 ? Math.ceil(midF) : Math.floor(midF)
if (mid == from) { return pred(mid) ? from : to }
if (pred(mid)) { to = mid }
else { from = mid }
else { from = mid + dir }
}
}
@ -897,12 +902,12 @@ function findMaxLine(cm) {
// BIDI HELPERS
function iterateBidiSections(order, from, to, f) {
if (!order) { return f(from, to, "ltr") }
if (!order) { return f(from, to, "ltr", 0) }
var found = false
for (var i = 0; i < order.length; ++i) {
var part = order[i]
if (part.from < to && part.to > from || from == to && part.to == from) {
f(Math.max(part.from, from), Math.min(part.to, to), part.level == 1 ? "rtl" : "ltr")
f(Math.max(part.from, from), Math.min(part.to, to), part.level == 1 ? "rtl" : "ltr", i)
found = true
}
}
@ -1105,112 +1110,6 @@ function getOrder(line, direction) {
return order
}
function moveCharLogically(line, ch, dir) {
var target = skipExtendingChars(line.text, ch + dir, dir)
return target < 0 || target > line.text.length ? null : target
}
function moveLogically(line, start, dir) {
var ch = moveCharLogically(line, start.ch, dir)
return ch == null ? null : new Pos(start.line, ch, dir < 0 ? "after" : "before")
}
function endOfLine(visually, cm, lineObj, lineNo, dir) {
if (visually) {
var order = getOrder(lineObj, cm.doc.direction)
if (order) {
var part = dir < 0 ? lst(order) : order[0]
var moveInStorageOrder = (dir < 0) == (part.level == 1)
var sticky = moveInStorageOrder ? "after" : "before"
var ch
// With a wrapped rtl chunk (possibly spanning multiple bidi parts),
// it could be that the last bidi part is not on the last visual line,
// since visual lines contain content order-consecutive chunks.
// Thus, in rtl, we are looking for the first (content-order) character
// in the rtl chunk that is on the last line (that is, the same line
// as the last (content-order) character).
if (part.level > 0) {
var prep = prepareMeasureForLine(cm, lineObj)
ch = dir < 0 ? lineObj.text.length - 1 : 0
var targetTop = measureCharPrepared(cm, prep, ch).top
ch = findFirst(function (ch) { return measureCharPrepared(cm, prep, ch).top == targetTop; }, (dir < 0) == (part.level == 1) ? part.from : part.to - 1, ch)
if (sticky == "before") { ch = moveCharLogically(lineObj, ch, 1) }
} else { ch = dir < 0 ? part.to : part.from }
return new Pos(lineNo, ch, sticky)
}
}
return new Pos(lineNo, dir < 0 ? lineObj.text.length : 0, dir < 0 ? "before" : "after")
}
function moveVisually(cm, line, start, dir) {
var bidi = getOrder(line, cm.doc.direction)
if (!bidi) { return moveLogically(line, start, dir) }
if (start.ch >= line.text.length) {
start.ch = line.text.length
start.sticky = "before"
} else if (start.ch <= 0) {
start.ch = 0
start.sticky = "after"
}
var partPos = getBidiPartAt(bidi, start.ch, start.sticky), part = bidi[partPos]
if (cm.doc.direction == "ltr" && part.level % 2 == 0 && (dir > 0 ? part.to > start.ch : part.from < start.ch)) {
// Case 1: We move within an ltr part in an ltr editor. Even with wrapped lines,
// nothing interesting happens.
return moveLogically(line, start, dir)
}
var mv = function (pos, dir) { return moveCharLogically(line, pos instanceof Pos ? pos.ch : pos, dir); }
var prep
var getWrappedLineExtent = function (ch) {
if (!cm.options.lineWrapping) { return {begin: 0, end: line.text.length} }
prep = prep || prepareMeasureForLine(cm, line)
return wrappedLineExtentChar(cm, line, prep, ch)
}
var wrappedLineExtent = getWrappedLineExtent(start.sticky == "before" ? mv(start, -1) : start.ch)
if (cm.doc.direction == "rtl" || part.level == 1) {
var moveInStorageOrder = (part.level == 1) == (dir < 0)
var ch = mv(start, moveInStorageOrder ? 1 : -1)
if (ch != null && (!moveInStorageOrder ? ch >= part.from && ch >= wrappedLineExtent.begin : ch <= part.to && ch <= wrappedLineExtent.end)) {
// Case 2: We move within an rtl part or in an rtl editor on the same visual line
var sticky = moveInStorageOrder ? "before" : "after"
return new Pos(start.line, ch, sticky)
}
}
// Case 3: Could not move within this bidi part in this visual line, so leave
// the current bidi part
var searchInVisualLine = function (partPos, dir, wrappedLineExtent) {
var getRes = function (ch, moveInStorageOrder) { return moveInStorageOrder
? new Pos(start.line, mv(ch, 1), "before")
: new Pos(start.line, ch, "after"); }
for (; partPos >= 0 && partPos < bidi.length; partPos += dir) {
var part = bidi[partPos]
var moveInStorageOrder = (dir > 0) == (part.level != 1)
var ch = moveInStorageOrder ? wrappedLineExtent.begin : mv(wrappedLineExtent.end, -1)
if (part.from <= ch && ch < part.to) { return getRes(ch, moveInStorageOrder) }
ch = moveInStorageOrder ? part.from : mv(part.to, -1)
if (wrappedLineExtent.begin <= ch && ch < wrappedLineExtent.end) { return getRes(ch, moveInStorageOrder) }
}
}
// Case 3a: Look for other bidi parts on the same visual line
var res = searchInVisualLine(partPos + dir, dir, wrappedLineExtent)
if (res) { return res }
// Case 3b: Look for other bidi parts on the next visual line
var nextCh = dir > 0 ? wrappedLineExtent.end : mv(wrappedLineExtent.begin, -1)
if (nextCh != null && !(dir > 0 && nextCh == line.text.length)) {
res = searchInVisualLine(dir > 0 ? 0 : bidi.length - 1, dir, getWrappedLineExtent(nextCh))
if (res) { return res }
}
// Case 4: Nowhere to move
return null
}
// EVENT HANDLING
// Lightweight event framework. on/off also work on DOM nodes,
@ -2719,15 +2618,22 @@ function pageScrollY() {
return window.pageYOffset || (document.documentElement || document.body).scrollTop
}
function widgetTopHeight(lineObj) {
var height = 0
if (lineObj.widgets) { for (var i = 0; i < lineObj.widgets.length; ++i) { if (lineObj.widgets[i].above)
{ height += widgetHeight(lineObj.widgets[i]) } } }
return height
}
// Converts a {top, bottom, left, right} box from line-local
// coordinates into another coordinate system. Context may be one of
// "line", "div" (display.lineDiv), "local"./null (editor), "window",
// or "page".
function intoCoordSystem(cm, lineObj, rect, context, includeWidgets) {
if (!includeWidgets && lineObj.widgets) { for (var i = 0; i < lineObj.widgets.length; ++i) { if (lineObj.widgets[i].above) {
var size = widgetHeight(lineObj.widgets[i])
rect.top += size; rect.bottom += size
} } }
if (!includeWidgets) {
var height = widgetTopHeight(lineObj)
rect.top += height; rect.bottom += height
}
if (context == "line") { return rect }
if (!context) { context = "local" }
var yOff = heightAtLine(lineObj)
@ -2802,7 +2708,7 @@ function cursorCoords(cm, pos, context, lineObj, preparedMeasure, varHeight) {
if (!order) { return get(sticky == "before" ? ch - 1 : ch, sticky == "before") }
function getBidi(ch, partPos, invert) {
var part = order[partPos], right = (part.level % 2) != 0
var part = order[partPos], right = part.level == 1
return get(invert ? ch - 1 : ch, right != invert)
}
var partPos = getBidiPartAt(order, ch, sticky)
@ -2860,77 +2766,146 @@ function coordsChar(cm, x, y) {
}
function wrappedLineExtent(cm, lineObj, preparedMeasure, y) {
var measure = function (ch) { return intoCoordSystem(cm, lineObj, measureCharPrepared(cm, preparedMeasure, ch), "line"); }
y -= widgetTopHeight(lineObj)
var end = lineObj.text.length
var begin = findFirst(function (ch) { return measure(ch - 1).bottom <= y; }, end, 0)
end = findFirst(function (ch) { return measure(ch).top > y; }, begin, end)
var begin = findFirst(function (ch) { return measureCharPrepared(cm, preparedMeasure, ch - 1).bottom <= y; }, end, 0)
end = findFirst(function (ch) { return measureCharPrepared(cm, preparedMeasure, ch).top > y; }, begin, end)
return {begin: begin, end: end}
}
function wrappedLineExtentChar(cm, lineObj, preparedMeasure, target) {
if (!preparedMeasure) { preparedMeasure = prepareMeasureForLine(cm, lineObj) }
var targetTop = intoCoordSystem(cm, lineObj, measureCharPrepared(cm, preparedMeasure, target), "line").top
return wrappedLineExtent(cm, lineObj, preparedMeasure, targetTop)
}
// Returns true if the given side of a box is after the given
// coordinates, in top-to-bottom, left-to-right order.
function boxIsAfter(box, x, y, left) {
return box.bottom <= y ? false : box.top > y ? true : (left ? box.left : box.right) > x
}
function coordsCharInner(cm, lineObj, lineNo, x, y) {
// Move y into line-local coordinate space
y -= heightAtLine(lineObj)
var begin = 0, end = lineObj.text.length
var preparedMeasure = prepareMeasureForLine(cm, lineObj)
var pos
// When directly calling `measureCharPrepared`, we have to adjust
// for the widgets at this line.
var widgetHeight = widgetTopHeight(lineObj)
var begin = 0, end = lineObj.text.length, ltr = true
var order = getOrder(lineObj, cm.doc.direction)
// If the line isn't plain left-to-right text, first figure out
// which bidi section the coordinates fall into.
if (order) {
if (cm.options.lineWrapping) {
;var assign;
((assign = wrappedLineExtent(cm, lineObj, preparedMeasure, y), begin = assign.begin, end = assign.end, assign))
}
pos = new Pos(lineNo, Math.floor(begin + (end - begin) / 2))
var beginLeft = cursorCoords(cm, pos, "line", lineObj, preparedMeasure).left
var dir = beginLeft < x ? 1 : -1
var prevDiff, diff = beginLeft - x, prevPos
var steps = Math.ceil((end - begin) / 4)
outer: do {
prevDiff = diff
prevPos = pos
var i = 0
for (; i < steps; ++i) {
var prevPos$1 = pos
pos = moveVisually(cm, lineObj, pos, dir)
if (pos == null || pos.ch < begin || end <= (pos.sticky == "before" ? pos.ch - 1 : pos.ch)) {
pos = prevPos$1
break outer
}
}
diff = cursorCoords(cm, pos, "line", lineObj, preparedMeasure).left - x
if (steps > 1) {
var diff_change_per_step = Math.abs(diff - prevDiff) / steps
steps = Math.min(steps, Math.ceil(Math.abs(diff) / diff_change_per_step))
dir = diff < 0 ? 1 : -1
}
} while (diff != 0 && (steps > 1 || ((dir < 0) != (diff < 0) && (Math.abs(diff) <= Math.abs(prevDiff)))))
if (Math.abs(diff) > Math.abs(prevDiff)) {
if ((diff < 0) == (prevDiff < 0)) { throw new Error("Broke out of infinite loop in coordsCharInner") }
pos = prevPos
}
} else {
var ch = findFirst(function (ch) {
var box = intoCoordSystem(cm, lineObj, measureCharPrepared(cm, preparedMeasure, ch), "line")
if (box.top > y) {
// For the cursor stickiness
end = Math.min(ch, end)
return true
}
else if (box.bottom <= y) { return false }
else if (box.left > x) { return true }
else if (box.right < x) { return false }
else { return (x - box.left < box.right - x) }
}, begin, end)
ch = skipExtendingChars(lineObj.text, ch, 1)
pos = new Pos(lineNo, ch, ch == end ? "before" : "after")
var part = (cm.options.lineWrapping ? coordsBidiPartWrapped : coordsBidiPart)
(cm, lineObj, lineNo, preparedMeasure, order, x, y)
ltr = part.level != 1
// The awkward -1 offsets are needed because findFirst (called
// on these below) will treat its first bound as inclusive,
// second as exclusive, but we want to actually address the
// characters in the part's range
begin = ltr ? part.from : part.to - 1
end = ltr ? part.to : part.from - 1
}
var coords = cursorCoords(cm, pos, "line", lineObj, preparedMeasure)
if (y < coords.top || coords.bottom < y) { pos.outside = true }
pos.xRel = x < coords.left ? -1 : (x > coords.right ? 1 : 0)
return pos
// A binary search to find the first character whose bounding box
// starts after the coordinates. If we run across any whose box wrap
// the coordinates, store that.
var chAround = null, boxAround = null
var ch = findFirst(function (ch) {
var box = measureCharPrepared(cm, preparedMeasure, ch)
box.top += widgetHeight; box.bottom += widgetHeight
if (!boxIsAfter(box, x, y, false)) { return false }
if (box.top <= y && box.left <= x) {
chAround = ch
boxAround = box
}
return true
}, begin, end)
var baseX, sticky, outside = false
// If a box around the coordinates was found, use that
if (boxAround) {
// Distinguish coordinates nearer to the left or right side of the box
var atLeft = x - boxAround.left < boxAround.right - x, atStart = atLeft == ltr
ch = chAround + (atStart ? 0 : 1)
sticky = atStart ? "after" : "before"
baseX = atLeft ? boxAround.left : boxAround.right
} else {
// (Adjust for extended bound, if necessary.)
if (!ltr && (ch == end || ch == begin)) { ch++ }
// To determine which side to associate with, get the box to the
// left of the character and compare it's vertical position to the
// coordinates
sticky = ch == 0 ? "after" : ch == lineObj.text.length ? "before" :
(measureCharPrepared(cm, preparedMeasure, ch - (ltr ? 1 : 0)).bottom + widgetHeight <= y) == ltr ?
"after" : "before"
// Now get accurate coordinates for this place, in order to get a
// base X position
var coords = cursorCoords(cm, Pos(lineNo, ch, sticky), "line", lineObj, preparedMeasure)
baseX = coords.left
outside = y < coords.top || y >= coords.bottom
}
ch = skipExtendingChars(lineObj.text, ch, 1)
return PosWithInfo(lineNo, ch, sticky, outside, x - baseX)
}
function coordsBidiPart(cm, lineObj, lineNo, preparedMeasure, order, x, y) {
// Bidi parts are sorted left-to-right, and in a non-line-wrapping
// situation, we can take this ordering to correspond to the visual
// ordering. This finds the first part whose end is after the given
// coordinates.
var index = findFirst(function (i) {
var part = order[i], ltr = part.level != 1
return boxIsAfter(cursorCoords(cm, Pos(lineNo, ltr ? part.to : part.from, ltr ? "before" : "after"),
"line", lineObj, preparedMeasure), x, y, true)
}, 0, order.length - 1)
var part = order[index]
// If this isn't the first part, the part's start is also after
// the coordinates, and the coordinates aren't on the same line as
// that start, move one part back.
if (index > 0) {
var ltr = part.level != 1
var start = cursorCoords(cm, Pos(lineNo, ltr ? part.from : part.to, ltr ? "after" : "before"),
"line", lineObj, preparedMeasure)
if (boxIsAfter(start, x, y, true) && start.top > y)
{ part = order[index - 1] }
}
return part
}
function coordsBidiPartWrapped(cm, lineObj, _lineNo, preparedMeasure, order, x, y) {
// In a wrapped line, rtl text on wrapping boundaries can do things
// that don't correspond to the ordering in our `order` array at
// all, so a binary search doesn't work, and we want to return a
// part that only spans one line so that the binary search in
// coordsCharInner is safe. As such, we first find the extent of the
// wrapped line, and then do a flat search in which we discard any
// spans that aren't on the line.
var ref = wrappedLineExtent(cm, lineObj, preparedMeasure, y);
var begin = ref.begin;
var end = ref.end;
var part = null, closestDist = null
for (var i = 0; i < order.length; i++) {
var p = order[i]
if (p.from >= end || p.to <= begin) { continue }
var ltr = p.level != 1
var endX = measureCharPrepared(cm, preparedMeasure, ltr ? Math.min(end, p.to) - 1 : Math.max(begin, p.from)).right
// Weigh against spans ending before this, so that they are only
// picked if nothing ends after
var dist = endX < x ? x - endX + 1e9 : endX - x
if (!part || closestDist > dist) {
part = p
closestDist = dist
}
}
if (!part) { part = order[order.length - 1] }
// Clip the part to the wrapped line.
if (part.from < begin) { part = {from: begin, to: part.to, level: part.level} }
if (part.to > end) { part = {from: part.from, to: end, level: part.level} }
return part
}
var measureText
@ -3056,12 +3031,14 @@ function updateSelection(cm) {
}
function prepareSelection(cm, primary) {
if ( primary === void 0 ) primary = true;
var doc = cm.doc, result = {}
var curFragment = result.cursors = document.createDocumentFragment()
var selFragment = result.selection = document.createDocumentFragment()
for (var i = 0; i < doc.sel.ranges.length; i++) {
if (primary === false && i == doc.sel.primIndex) { continue }
if (!primary && i == doc.sel.primIndex) { continue }
var range = doc.sel.ranges[i]
if (range.from().line >= cm.display.viewTo || range.to().line < cm.display.viewFrom) { continue }
var collapsed = range.empty()
@ -3092,6 +3069,8 @@ function drawSelectionCursor(cm, head, output) {
}
}
function cmpCoords(a, b) { return a.top - b.top || a.left - b.left }
// Draws the given range as a highlighted selection
function drawSelectionRange(cm, range, output) {
var display = cm.display, doc = cm.doc
@ -3114,30 +3093,48 @@ function drawSelectionRange(cm, range, output) {
return charCoords(cm, Pos(line, ch), "div", lineObj, bias)
}
iterateBidiSections(getOrder(lineObj, doc.direction), fromArg || 0, toArg == null ? lineLen : toArg, function (from, to, dir) {
var leftPos = coords(from, "left"), rightPos, left, right
if (from == to) {
rightPos = leftPos
left = right = leftPos.left
} else {
rightPos = coords(to - 1, "right")
if (dir == "rtl") { var tmp = leftPos; leftPos = rightPos; rightPos = tmp }
left = leftPos.left
right = rightPos.right
var order = getOrder(lineObj, doc.direction)
iterateBidiSections(order, fromArg || 0, toArg == null ? lineLen : toArg, function (from, to, dir, i) {
var fromPos = coords(from, dir == "ltr" ? "left" : "right")
var toPos = coords(to - 1, dir == "ltr" ? "right" : "left")
if (dir == "ltr") {
var fromLeft = fromArg == null && from == 0 ? leftSide : fromPos.left
var toRight = toArg == null && to == lineLen ? rightSide : toPos.right
if (toPos.top - fromPos.top <= 3) { // Single line
add(fromLeft, toPos.top, toRight - fromLeft, toPos.bottom)
} else { // Multiple lines
add(fromLeft, fromPos.top, null, fromPos.bottom)
if (fromPos.bottom < toPos.top) { add(leftSide, fromPos.bottom, null, toPos.top) }
add(leftSide, toPos.top, toPos.right, toPos.bottom)
}
} else if (from < to) { // RTL
var fromRight = fromArg == null && from == 0 ? rightSide : fromPos.right
var toLeft = toArg == null && to == lineLen ? leftSide : toPos.left
if (toPos.top - fromPos.top <= 3) { // Single line
add(toLeft, toPos.top, fromRight - toLeft, toPos.bottom)
} else { // Multiple lines
var topLeft = leftSide
if (i) {
var topEnd = wrappedLineExtentChar(cm, lineObj, null, from).end
// The coordinates returned for an RTL wrapped space tend to
// be complete bogus, so try to skip that here.
topLeft = coords(topEnd - (/\s/.test(lineObj.text.charAt(topEnd - 1)) ? 2 : 1), "left").left
}
add(topLeft, fromPos.top, fromRight - topLeft, fromPos.bottom)
if (fromPos.bottom < toPos.top) { add(leftSide, fromPos.bottom, null, toPos.top) }
var botWidth = null
if (i < order.length - 1 || true) {
var botStart = wrappedLineExtentChar(cm, lineObj, null, to).begin
botWidth = coords(botStart, "right").right - toLeft
}
add(toLeft, toPos.top, botWidth, toPos.bottom)
}
}
if (fromArg == null && from == 0) { left = leftSide }
if (rightPos.top - leftPos.top > 3) { // Different lines, draw top part
add(left, leftPos.top, null, leftPos.bottom)
left = leftSide
if (leftPos.bottom < rightPos.top) { add(left, leftPos.bottom, null, rightPos.top) }
}
if (toArg == null && to == lineLen) { right = rightSide }
if (!start || leftPos.top < start.top || leftPos.top == start.top && leftPos.left < start.left)
{ start = leftPos }
if (!end || rightPos.bottom > end.bottom || rightPos.bottom == end.bottom && rightPos.right > end.right)
{ end = rightPos }
if (left < leftSide + 1) { left = leftSide }
add(left, rightPos.top, right - left, rightPos.bottom)
if (!start || cmpCoords(fromPos, start) < 0) { start = fromPos }
if (cmpCoords(toPos, start) < 0) { start = toPos }
if (!end || cmpCoords(fromPos, end) < 0) { end = fromPos }
if (cmpCoords(toPos, end) < 0) { end = toPos }
})
return {start: start, end: end}
}
@ -3767,7 +3764,7 @@ function endOperation_R2(op) {
}
if (op.updatedDisplay || op.selectionChanged)
{ op.preparedSelection = display.input.prepareSelection(op.focus) }
{ op.preparedSelection = display.input.prepareSelection() }
}
function endOperation_W2(op) {
@ -3780,7 +3777,7 @@ function endOperation_W2(op) {
cm.display.maxLineChanged = false
}
var takeFocus = op.focus && op.focus == activeElt() && (!document.hasFocus || document.hasFocus())
var takeFocus = op.focus && op.focus == activeElt()
if (op.preparedSelection)
{ cm.display.input.showSelection(op.preparedSelection, takeFocus) }
if (op.updatedDisplay || op.startHeight != cm.doc.height)
@ -5369,7 +5366,8 @@ function makeChangeSingleDocInEditor(cm, change, spans) {
function replaceRange(doc, code, from, to, origin) {
if (!to) { to = from }
if (cmp(to, from) < 0) { var tmp = to; to = from; from = tmp }
if (cmp(to, from) < 0) { var assign;
(assign = [to, from], from = assign[0], to = assign[1], assign) }
if (typeof code == "string") { code = doc.splitLines(code) }
makeChange(doc, {from: from, to: to, text: code, origin: origin})
}
@ -6731,6 +6729,112 @@ function deleteNearSelection(cm, compute) {
})
}
function moveCharLogically(line, ch, dir) {
var target = skipExtendingChars(line.text, ch + dir, dir)
return target < 0 || target > line.text.length ? null : target
}
function moveLogically(line, start, dir) {
var ch = moveCharLogically(line, start.ch, dir)
return ch == null ? null : new Pos(start.line, ch, dir < 0 ? "after" : "before")
}
function endOfLine(visually, cm, lineObj, lineNo, dir) {
if (visually) {
var order = getOrder(lineObj, cm.doc.direction)
if (order) {
var part = dir < 0 ? lst(order) : order[0]
var moveInStorageOrder = (dir < 0) == (part.level == 1)
var sticky = moveInStorageOrder ? "after" : "before"
var ch
// With a wrapped rtl chunk (possibly spanning multiple bidi parts),
// it could be that the last bidi part is not on the last visual line,
// since visual lines contain content order-consecutive chunks.
// Thus, in rtl, we are looking for the first (content-order) character
// in the rtl chunk that is on the last line (that is, the same line
// as the last (content-order) character).
if (part.level > 0) {
var prep = prepareMeasureForLine(cm, lineObj)
ch = dir < 0 ? lineObj.text.length - 1 : 0
var targetTop = measureCharPrepared(cm, prep, ch).top
ch = findFirst(function (ch) { return measureCharPrepared(cm, prep, ch).top == targetTop; }, (dir < 0) == (part.level == 1) ? part.from : part.to - 1, ch)
if (sticky == "before") { ch = moveCharLogically(lineObj, ch, 1) }
} else { ch = dir < 0 ? part.to : part.from }
return new Pos(lineNo, ch, sticky)
}
}
return new Pos(lineNo, dir < 0 ? lineObj.text.length : 0, dir < 0 ? "before" : "after")
}
function moveVisually(cm, line, start, dir) {
var bidi = getOrder(line, cm.doc.direction)
if (!bidi) { return moveLogically(line, start, dir) }
if (start.ch >= line.text.length) {
start.ch = line.text.length
start.sticky = "before"
} else if (start.ch <= 0) {
start.ch = 0
start.sticky = "after"
}
var partPos = getBidiPartAt(bidi, start.ch, start.sticky), part = bidi[partPos]
if (cm.doc.direction == "ltr" && part.level % 2 == 0 && (dir > 0 ? part.to > start.ch : part.from < start.ch)) {
// Case 1: We move within an ltr part in an ltr editor. Even with wrapped lines,
// nothing interesting happens.
return moveLogically(line, start, dir)
}
var mv = function (pos, dir) { return moveCharLogically(line, pos instanceof Pos ? pos.ch : pos, dir); }
var prep
var getWrappedLineExtent = function (ch) {
if (!cm.options.lineWrapping) { return {begin: 0, end: line.text.length} }
prep = prep || prepareMeasureForLine(cm, line)
return wrappedLineExtentChar(cm, line, prep, ch)
}
var wrappedLineExtent = getWrappedLineExtent(start.sticky == "before" ? mv(start, -1) : start.ch)
if (cm.doc.direction == "rtl" || part.level == 1) {
var moveInStorageOrder = (part.level == 1) == (dir < 0)
var ch = mv(start, moveInStorageOrder ? 1 : -1)
if (ch != null && (!moveInStorageOrder ? ch >= part.from && ch >= wrappedLineExtent.begin : ch <= part.to && ch <= wrappedLineExtent.end)) {
// Case 2: We move within an rtl part or in an rtl editor on the same visual line
var sticky = moveInStorageOrder ? "before" : "after"
return new Pos(start.line, ch, sticky)
}
}
// Case 3: Could not move within this bidi part in this visual line, so leave
// the current bidi part
var searchInVisualLine = function (partPos, dir, wrappedLineExtent) {
var getRes = function (ch, moveInStorageOrder) { return moveInStorageOrder
? new Pos(start.line, mv(ch, 1), "before")
: new Pos(start.line, ch, "after"); }
for (; partPos >= 0 && partPos < bidi.length; partPos += dir) {
var part = bidi[partPos]
var moveInStorageOrder = (dir > 0) == (part.level != 1)
var ch = moveInStorageOrder ? wrappedLineExtent.begin : mv(wrappedLineExtent.end, -1)
if (part.from <= ch && ch < part.to) { return getRes(ch, moveInStorageOrder) }
ch = moveInStorageOrder ? part.from : mv(part.to, -1)
if (wrappedLineExtent.begin <= ch && ch < wrappedLineExtent.end) { return getRes(ch, moveInStorageOrder) }
}
}
// Case 3a: Look for other bidi parts on the same visual line
var res = searchInVisualLine(partPos + dir, dir, wrappedLineExtent)
if (res) { return res }
// Case 3b: Look for other bidi parts on the next visual line
var nextCh = dir > 0 ? wrappedLineExtent.end : mv(wrappedLineExtent.begin, -1)
if (nextCh != null && !(dir > 0 && nextCh == line.text.length)) {
res = searchInVisualLine(dir > 0 ? 0 : bidi.length - 1, dir, getWrappedLineExtent(nextCh))
if (res) { return res }
}
// Case 4: Nowhere to move
return null
}
// Commands are parameter-less actions that can be performed on an
// editor, mostly used for keybindings.
var commands = {
@ -7292,7 +7396,7 @@ function leftButtonSelect(cm, event, start, behavior) {
anchor = maxPos(oldRange.to(), range.head)
}
var ranges$1 = startSel.ranges.slice(0)
ranges$1[ourIndex] = new Range(clipPos(doc, anchor), head)
ranges$1[ourIndex] = bidiSimplify(cm, new Range(clipPos(doc, anchor), head))
setSelection(doc, normalizeSelection(ranges$1, ourIndex), sel_mouse)
}
}
@ -7344,13 +7448,52 @@ function leftButtonSelect(cm, event, start, behavior) {
on(document, "mouseup", up)
}
// Used when mouse-selecting to adjust the anchor to the proper side
// of a bidi jump depending on the visual position of the head.
function bidiSimplify(cm, range) {
var anchor = range.anchor;
var head = range.head;
var anchorLine = getLine(cm.doc, anchor.line)
if (cmp(anchor, head) == 0 && anchor.sticky == head.sticky) { return range }
var order = getOrder(anchorLine)
if (!order) { return range }
var index = getBidiPartAt(order, anchor.ch, anchor.sticky), part = order[index]
if (part.from != anchor.ch && part.to != anchor.ch) { return range }
var boundary = index + ((part.from == anchor.ch) == (part.level != 1) ? 0 : 1)
if (boundary == 0 || boundary == order.length) { return range }
// Compute the relative visual position of the head compared to the
// anchor (<0 is to the left, >0 to the right)
var leftSide
if (head.line != anchor.line) {
leftSide = (head.line - anchor.line) * (cm.doc.direction == "ltr" ? 1 : -1) > 0
} else {
var headIndex = getBidiPartAt(order, head.ch, head.sticky)
var dir = headIndex - index || (head.ch - anchor.ch) * (part.level == 1 ? -1 : 1)
if (headIndex == boundary - 1 || headIndex == boundary)
{ leftSide = dir < 0 }
else
{ leftSide = dir > 0 }
}
var usePart = order[boundary + (leftSide ? -1 : 0)]
var from = leftSide == (usePart.level == 1)
var ch = from ? usePart.from : usePart.to, sticky = from ? "after" : "before"
return anchor.ch == ch && anchor.sticky == sticky ? range : new Range(new Pos(anchor.line, ch, sticky), head)
}
// Determines whether an event happened in the gutter, and fires the
// handlers for the corresponding event.
function gutterEvent(cm, e, type, prevent) {
var mX, mY
try { mX = e.clientX; mY = e.clientY }
catch(e) { return false }
if (e.touches) {
mX = e.touches[0].clientX
mY = e.touches[0].clientY
} else {
try { mX = e.clientX; mY = e.clientY }
catch(e) { return false }
}
if (mX >= Math.floor(cm.display.gutters.getBoundingClientRect().right)) { return false }
if (prevent) { e_preventDefault(e) }
@ -7688,7 +7831,7 @@ function registerEventHandlers(cm) {
return dx * dx + dy * dy > 20 * 20
}
on(d.scroller, "touchstart", function (e) {
if (!signalDOMEvent(cm, e) && !isMouseLikeTouchEvent(e)) {
if (!signalDOMEvent(cm, e) && !isMouseLikeTouchEvent(e) && !clickInGutter(cm, e)) {
d.input.ensurePolled()
clearTimeout(touchFinished)
var now = +new Date
@ -9472,7 +9615,7 @@ CodeMirror.fromTextArea = fromTextArea
addLegacyProps(CodeMirror)
CodeMirror.version = "5.29.0"
CodeMirror.version = "5.30.0"
return CodeMirror;

Просмотреть файл

@ -28,7 +28,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
var jsKeywords = {
"if": kw("if"), "while": A, "with": A, "else": B, "do": B, "try": B, "finally": B,
"return": C, "break": C, "continue": C, "new": kw("new"), "delete": C, "throw": C, "debugger": C,
"return": C, "break": C, "continue": C, "new": kw("new"), "delete": C, "void": C, "throw": C, "debugger": C,
"var": kw("var"), "const": kw("var"), "let": kw("var"),
"function": kw("function"), "catch": kw("catch"),
"for": kw("for"), "switch": kw("switch"), "case": kw("case"), "default": kw("default"),
@ -398,7 +398,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
function expressionInner(type, noComma) {
if (cx.state.fatArrowAt == cx.stream.start) {
var body = noComma ? arrowBodyNoComma : arrowBody;
if (type == "(") return cont(pushcontext, pushlex(")"), commasep(pattern, ")"), poplex, expect("=>"), body, popcontext);
if (type == "(") return cont(pushcontext, pushlex(")"), commasep(funarg, ")"), poplex, expect("=>"), body, popcontext);
else if (type == "variable") return pass(pushcontext, pattern, expect("=>"), body, popcontext);
}
@ -443,6 +443,11 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
if (type == ".") return cont(property, me);
if (type == "[") return cont(pushlex("]"), maybeexpression, expect("]"), poplex, me);
if (isTS && value == "as") { cx.marked = "keyword"; return cont(typeexpr, me) }
if (type == "regexp") {
cx.state.lastType = cx.marked = "operator"
cx.stream.backUp(cx.stream.pos - cx.stream.start - 1)
return cont(expr)
}
}
function quasi(type, value) {
if (type != "quasi") return pass();
@ -491,6 +496,9 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
} else if (type == "variable" || cx.style == "keyword") {
cx.marked = "property";
if (value == "get" || value == "set") return cont(getterSetter);
var m // Work around fat-arrow-detection complication for detecting typescript typed arrow params
if (isTS && cx.state.fatArrowAt == cx.stream.start && (m = cx.stream.match(/^\s*:\s*/, false)))
cx.state.fatArrowAt = cx.stream.pos + m[0].length
return cont(afterprop);
} else if (type == "number" || type == "string") {
cx.marked = jsonldMode ? "property" : (cx.style + " property");
@ -648,7 +656,8 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
if (type == "(") return cont(pushcontext, pushlex(")"), commasep(funarg, ")"), poplex, maybetype, statement, popcontext);
if (isTS && value == "<") return cont(pushlex(">"), commasep(typeexpr, ">"), poplex, functiondef)
}
function funarg(type) {
function funarg(type, value) {
if (value == "@") cont(expression, funarg)
if (type == "spread" || type == "modifier") return cont(funarg);
return pass(pattern, maybetype, maybeAssign);
}
@ -674,7 +683,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
cx.marked = "keyword";
return cont(classBody);
}
if (type == "variable") {
if (type == "variable" || cx.style == "keyword") {
cx.marked = "property";
return cont(isTS ? classfield : functiondef, classBody);
}
@ -736,7 +745,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
function expressionAllowed(stream, state, backUp) {
return state.tokenize == tokenBase &&
/^(?:operator|sof|keyword c|case|new|export|default|[\[{}\(,;:]|=>)$/.test(state.lastType) ||
/^(?:operator|sof|keyword [bc]|case|new|export|default|spread|[\[{}\(,;:]|=>)$/.test(state.lastType) ||
(state.lastType == "quasi" && /\{\s*$/.test(stream.string.slice(0, stream.pos - (backUp || 0))))
}

Просмотреть файл

@ -254,6 +254,11 @@ testCM("coordsCharBidi", function(cm) {
}
}, {lineNumbers: true});
testCM("badBidiOptimization", function(cm) {
var coords = cm.charCoords(Pos(0, 34))
eqCharPos(cm.coordsChar({left: coords.right, top: coords.top + 2}), Pos(0, 34))
}, {value: "----------<p class=\"title\">هل يمكنك اختيار مستوى قسط التأمين الذي ترغب بدفعه؟</p>"})
testCM("posFromIndex", function(cm) {
cm.setValue(
"This function should\n" +
@ -1156,6 +1161,16 @@ testCM("measureWrappedEndOfLine", function(cm) {
}
}, {mode: "text/html", value: "0123456789abcde0123456789", lineWrapping: true}, ie_lt8 || opera_lt10);
testCM("measureEndOfLineBidi", function(cm) {
eqCursorPos(cm.coordsChar({left: 5000, top: cm.charCoords(Pos(0, 0)).top}), Pos(0, 8, "after"))
}, {value: "إإإإuuuuإإإإ"})
testCM("measureWrappedBidiLevel2", function(cm) {
cm.setSize(cm.charCoords(Pos(0, 6), "editor").right + 60)
var c9 = cm.charCoords(Pos(0, 9))
eqCharPos(cm.coordsChar({left: c9.right - 1, top: c9.top + 1}), Pos(0, 9))
}, {value: "foobar إإ إإ إإ إإ 555 بببببب", lineWrapping: true})
testCM("measureWrappedBeginOfLine", function(cm) {
if (phantom) return;
cm.setSize(null, "auto");
@ -2468,6 +2483,23 @@ for (var i = 0; i < 5; ++i) {
}
*/
testCM("rtl_wrapped_selection", function(cm) {
cm.setSelection(Pos(0, 10), Pos(0, 190))
is(byClassName(cm.getWrapperElement(), "CodeMirror-selected").length >= 3)
}, {value: new Array(10).join(" فتي تم تضمينها فتي تم"), lineWrapping: true})
testCM("bidi_wrapped_selection", function(cm) {
if (phantom) return
cm.setSize(cm.charCoords(Pos(0, 10), "editor").left)
cm.setSelection(Pos(0, 37), Pos(0, 80))
var blocks = byClassName(cm.getWrapperElement(), "CodeMirror-selected")
is(blocks.length >= 2)
is(blocks.length <= 3)
var boxTop = blocks[0].getBoundingClientRect(), boxBot = blocks[blocks.length - 1].getBoundingClientRect()
is(boxTop.left > cm.charCoords(Pos(0, 1)).right)
is(boxBot.right < cm.charCoords(Pos(0, cm.getLine(0).length - 2)).left)
}, {value: "<p>مفتي11 تم تضمينهفتي تم تضمينها فتي تفتي تم تضمينها فتي تفتي تم تضمينها فتي تفتي تم تضمينها فتي تا فت10ي ت</p>", lineWrapping: true})
testCM("delete_wrapped", function(cm) {
makeItWrapAfter(cm, Pos(0, 2));
cm.doc.setCursor(Pos(0, 3, "after"));

Просмотреть файл

@ -8,7 +8,6 @@
#include "nsContentUtils.h"
#include "mozilla/dom/XBLChildrenElement.h"
#include "mozilla/dom/HTMLContentElement.h"
#include "mozilla/dom/HTMLShadowElement.h"
#include "mozilla/dom/ShadowRoot.h"
#include "nsIAnonymousContentCreator.h"
#include "nsIFrame.h"
@ -78,17 +77,6 @@ ExplicitChildIterator::GetNextChild()
}
mIndexInInserted = 0;
mChild = mChild->GetNextSibling();
} else if (mShadowIterator) {
// If we're inside of a <shadow> element, look through the
// explicit children of the projected ShadowRoot via
// the mShadowIterator.
nsIContent* nextChild = mShadowIterator->GetNextChild();
if (nextChild) {
return nextChild;
}
mShadowIterator = nullptr;
mChild = mChild->GetNextSibling();
} else if (mDefaultChild) {
// If we're already in default content, check if there are more nodes there
MOZ_ASSERT(mChild);
@ -110,23 +98,7 @@ ExplicitChildIterator::GetNextChild()
// Iterate until we find a non-insertion point, or an insertion point with
// content.
while (mChild) {
// If the current child being iterated is a shadow insertion point then
// the iterator needs to go into the projected ShadowRoot.
if (ShadowRoot::IsShadowInsertionPoint(mChild)) {
// Look for the next child in the projected ShadowRoot for the <shadow>
// element.
HTMLShadowElement* shadowElem = HTMLShadowElement::FromContent(mChild);
ShadowRoot* projectedShadow = shadowElem->GetOlderShadowRoot();
if (projectedShadow) {
mShadowIterator = new ExplicitChildIterator(projectedShadow);
nsIContent* nextChild = mShadowIterator->GetNextChild();
if (nextChild) {
return nextChild;
}
mShadowIterator = nullptr;
}
mChild = mChild->GetNextSibling();
} else if (nsContentUtils::IsContentInsertionPoint(mChild)) {
if (nsContentUtils::IsContentInsertionPoint(mChild)) {
// If the current child being iterated is a content insertion point
// then the iterator needs to return the nodes distributed into
// the content insertion point.
@ -196,11 +168,9 @@ ExplicitChildIterator::Seek(nsIContent* aChildToFind)
!aChildToFind->IsRootOfAnonymousSubtree()) {
// Fast path: just point ourselves to aChildToFind, which is a
// normal DOM child of ours.
MOZ_ASSERT(!ShadowRoot::IsShadowInsertionPoint(aChildToFind));
MOZ_ASSERT(!nsContentUtils::IsContentInsertionPoint(aChildToFind));
mChild = aChildToFind;
mIndexInInserted = 0;
mShadowIterator = nullptr;
mDefaultChild = nullptr;
mIsFirst = false;
return true;
@ -221,9 +191,8 @@ ExplicitChildIterator::Get() const
if (mIndexInInserted) {
MatchedNodes assignedChildren = GetMatchedNodesForPoint(mChild);
return assignedChildren[mIndexInInserted - 1];
} else if (mShadowIterator) {
return mShadowIterator->Get();
}
return mDefaultChild ? mDefaultChild : mChild;
}
@ -239,13 +208,6 @@ ExplicitChildIterator::GetPreviousChild()
return assignedChildren[mIndexInInserted - 1];
}
mChild = mChild->GetPreviousSibling();
} else if (mShadowIterator) {
nsIContent* previousChild = mShadowIterator->GetPreviousChild();
if (previousChild) {
return previousChild;
}
mShadowIterator = nullptr;
mChild = mChild->GetPreviousSibling();
} else if (mDefaultChild) {
// If we're already in default content, check if there are more nodes there
mDefaultChild = mDefaultChild->GetPreviousSibling();
@ -265,22 +227,7 @@ ExplicitChildIterator::GetPreviousChild()
// Iterate until we find a non-insertion point, or an insertion point with
// content.
while (mChild) {
if (ShadowRoot::IsShadowInsertionPoint(mChild)) {
// If the current child being iterated is a shadow insertion point then
// the iterator needs to go into the projected ShadowRoot.
HTMLShadowElement* shadowElem = HTMLShadowElement::FromContent(mChild);
ShadowRoot* projectedShadow = shadowElem->GetOlderShadowRoot();
if (projectedShadow) {
// Create a ExplicitChildIterator that begins iterating from the end.
mShadowIterator = new ExplicitChildIterator(projectedShadow, false);
nsIContent* previousChild = mShadowIterator->GetPreviousChild();
if (previousChild) {
return previousChild;
}
mShadowIterator = nullptr;
}
mChild = mChild->GetPreviousSibling();
} else if (nsContentUtils::IsContentInsertionPoint(mChild)) {
if (nsContentUtils::IsContentInsertionPoint(mChild)) {
// If the current child being iterated is a content insertion point
// then the iterator needs to return the nodes distributed into
// the content insertion point.

Просмотреть файл

@ -48,16 +48,12 @@ public:
ExplicitChildIterator(const ExplicitChildIterator& aOther)
: mParent(aOther.mParent), mChild(aOther.mChild),
mDefaultChild(aOther.mDefaultChild),
mShadowIterator(aOther.mShadowIterator ?
new ExplicitChildIterator(*aOther.mShadowIterator) :
nullptr),
mIsFirst(aOther.mIsFirst),
mIndexInInserted(aOther.mIndexInInserted) {}
ExplicitChildIterator(ExplicitChildIterator&& aOther)
: mParent(aOther.mParent), mChild(aOther.mChild),
mDefaultChild(aOther.mDefaultChild),
mShadowIterator(Move(aOther.mShadowIterator)),
mIsFirst(aOther.mIsFirst),
mIndexInInserted(aOther.mIndexInInserted) {}
@ -116,11 +112,6 @@ protected:
// to null, we continue iterating at mChild's next sibling.
nsIContent* mDefaultChild;
// If non-null, this points to an iterator of the explicit children of
// the ShadowRoot projected by the current shadow element that we're
// iterating.
nsAutoPtr<ExplicitChildIterator> mShadowIterator;
// A flag to let us know that we haven't started iterating yet.
bool mIsFirst;

Просмотреть файл

@ -939,7 +939,7 @@ DoUpgrade(Element* aElement,
} // anonymous namespace
// https://html.spec.whatwg.org/multipage/scripting.html#upgrades
void
/* static */ void
CustomElementRegistry::Upgrade(Element* aElement,
CustomElementDefinition* aDefinition,
ErrorResult& aRv)
@ -977,8 +977,10 @@ CustomElementRegistry::Upgrade(Element* aElement,
(attrValue.IsEmpty() ? VoidString() : attrValue),
(namespaceURI.IsEmpty() ? VoidString() : namespaceURI)
};
EnqueueLifecycleCallback(nsIDocument::eAttributeChanged, aElement,
&args, aDefinition);
nsContentUtils::EnqueueLifecycleCallback(aElement->OwnerDoc(),
nsIDocument::eAttributeChanged,
aElement,
&args, aDefinition);
}
}
}
@ -1003,7 +1005,9 @@ CustomElementRegistry::Upgrade(Element* aElement,
data->mState = CustomElementData::State::eCustom;
// This is for old spec.
EnqueueLifecycleCallback(nsIDocument::eCreated, aElement, nullptr, aDefinition);
nsContentUtils::EnqueueLifecycleCallback(aElement->OwnerDoc(),
nsIDocument::eCreated,
aElement, nullptr, aDefinition);
}
//-----------------------------------------------------

Просмотреть файл

@ -362,11 +362,15 @@ public:
void GetCustomPrototype(nsIAtom* aAtom,
JS::MutableHandle<JSObject*> aPrototype);
void SyncInvokeReactions(nsIDocument::ElementCallbackType aType,
Element* aCustomElement,
CustomElementDefinition* aDefinition);
/**
* Upgrade an element.
* https://html.spec.whatwg.org/multipage/scripting.html#upgrades
*/
void Upgrade(Element* aElement, CustomElementDefinition* aDefinition, ErrorResult& aRv);
static void Upgrade(Element* aElement, CustomElementDefinition* aDefinition, ErrorResult& aRv);
private:
~CustomElementRegistry();
@ -375,9 +379,6 @@ private:
nsIDocument::ElementCallbackType aType, Element* aCustomElement,
LifecycleCallbackArgs* aArgs, CustomElementDefinition* aDefinition);
void SyncInvokeReactions(nsIDocument::ElementCallbackType aType,
Element* aCustomElement,
CustomElementDefinition* aDefinition);
/**
* Registers an unresolved custom element that is a candidate for
* upgrade when the definition is registered via registerElement.

Просмотреть файл

@ -111,9 +111,7 @@ DocumentFragment::Constructor(const GlobalObject& aGlobal,
return window->GetDoc()->CreateDocumentFragment();
}
NS_IMPL_CYCLE_COLLECTION_INHERITED(DocumentFragment,
FragmentOrElement,
mHost)
NS_IMPL_CYCLE_COLLECTION_INHERITED(DocumentFragment, FragmentOrElement, mHost)
// QueryInterface implementation for DocumentFragment
NS_INTERFACE_MAP_BEGIN(DocumentFragment)

Просмотреть файл

@ -43,8 +43,7 @@ public:
// nsISupports
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(DocumentFragment,
FragmentOrElement)
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(DocumentFragment, FragmentOrElement)
// interface nsIDOMNode
NS_FORWARD_NSIDOMNODE_TO_NSINODE
@ -122,15 +121,9 @@ public:
return nullptr;
}
Element* GetHost() const
{
return mHost;
}
Element* GetHost() const { return mHost; }
void SetHost(Element* aHost)
{
mHost = aHost;
}
void SetHost(Element* aHost) { mHost = aHost; }
static already_AddRefed<DocumentFragment>
Constructor(const GlobalObject& aGlobal, ErrorResult& aRv);

Просмотреть файл

@ -1106,6 +1106,11 @@ Element::RemoveFromIdTable()
already_AddRefed<ShadowRoot>
Element::CreateShadowRoot(ErrorResult& aError)
{
if (GetShadowRoot()) {
aError.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
return nullptr;
}
nsAutoScriptBlocker scriptBlocker;
RefPtr<mozilla::dom::NodeInfo> nodeInfo;
@ -1142,24 +1147,7 @@ Element::CreateShadowRoot(ErrorResult& aError)
shadowRoot->SetIsComposedDocParticipant(IsInComposedDoc());
// Replace the old ShadowRoot with the new one and let the old
// ShadowRoot know about the younger ShadowRoot because the old
// ShadowRoot is projected into the younger ShadowRoot's shadow
// insertion point (if it exists).
ShadowRoot* olderShadow = GetShadowRoot();
SetShadowRoot(shadowRoot);
if (olderShadow) {
olderShadow->SetYoungerShadow(shadowRoot);
// Unbind children of older shadow root because they
// are no longer in the composed tree.
for (nsIContent* child = olderShadow->GetFirstChild(); child;
child = child->GetNextSibling()) {
child->UnbindFromTree(true, false);
}
olderShadow->SetIsComposedDocParticipant(false);
}
// xblBinding takes ownership of docInfo.
RefPtr<nsXBLBinding> xblBinding = new nsXBLBinding(shadowRoot, protoBinding);

Просмотреть файл

@ -1047,23 +1047,10 @@ nsIContent::GetEventTargetParent(EventChainPreVisitor& aVisitor)
// for destination insertion points where nodes have been distributed.
nsTArray<nsIContent*>* destPoints = GetExistingDestInsertionPoints();
if (destPoints && !destPoints->IsEmpty()) {
// Push destination insertion points to aVisitor.mDestInsertionPoints
// excluding shadow insertion points.
bool didPushNonShadowInsertionPoint = false;
// Push destination insertion points to aVisitor.mDestInsertionPoints.
for (uint32_t i = 0; i < destPoints->Length(); i++) {
nsIContent* point = destPoints->ElementAt(i);
if (!ShadowRoot::IsShadowInsertionPoint(point)) {
aVisitor.mDestInsertionPoints.AppendElement(point);
didPushNonShadowInsertionPoint = true;
}
}
// Next node in the event path is the final destination
// (non-shadow) insertion point that was pushed.
if (didPushNonShadowInsertionPoint) {
parent = aVisitor.mDestInsertionPoints.LastElement();
aVisitor.mDestInsertionPoints.SetLength(
aVisitor.mDestInsertionPoints.Length() - 1);
aVisitor.mDestInsertionPoints.AppendElement(point);
}
}
@ -1087,10 +1074,7 @@ nsIContent::GetEventTargetParent(EventChainPreVisitor& aVisitor)
aVisitor.mDestInsertionPoints.SetLength(
aVisitor.mDestInsertionPoints.Length() - 1);
} else {
// The pool host for the youngest shadow root is shadow DOM host,
// for older shadow roots, it is the shadow insertion point
// where the shadow root is projected, nullptr if none exists.
parent = thisShadowRoot->GetPoolHost();
parent = thisShadowRoot->GetHost();
}
}
@ -2619,8 +2603,7 @@ FragmentOrElement::SetIsElementInStyleScopeFlagOnShadowTree(bool aInStyleScope)
NS_ASSERTION(IsElement(), "calling SetIsElementInStyleScopeFlagOnShadowTree "
"on a non-Element is useless");
ShadowRoot* shadowRoot = GetShadowRoot();
while (shadowRoot) {
if (shadowRoot) {
shadowRoot->SetIsElementInStyleScopeFlagOnSubtree(aInStyleScope);
shadowRoot = shadowRoot->GetOlderShadowRoot();
}
}

Просмотреть файл

@ -15,7 +15,6 @@
#include "nsIStyleSheetLinkingElement.h"
#include "mozilla/dom/Element.h"
#include "mozilla/dom/HTMLContentElement.h"
#include "mozilla/dom/HTMLShadowElement.h"
#include "nsXBLPrototypeBinding.h"
#include "mozilla/StyleSheet.h"
#include "mozilla/StyleSheetInlines.h"
@ -27,10 +26,7 @@ NS_IMPL_CYCLE_COLLECTION_CLASS(ShadowRoot)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(ShadowRoot,
DocumentFragment)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPoolHost)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mStyleSheetList)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOlderShadow)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mYoungerShadow)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAssociatedBinding)
for (auto iter = tmp->mIdentifierMap.ConstIter(); !iter.Done();
iter.Next()) {
@ -38,18 +34,14 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(ShadowRoot,
}
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(ShadowRoot,
DocumentFragment)
if (tmp->mPoolHost) {
tmp->mPoolHost->RemoveMutationObserver(tmp);
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(ShadowRoot)
if (tmp->GetHost()) {
tmp->GetHost()->RemoveMutationObserver(tmp);
}
NS_IMPL_CYCLE_COLLECTION_UNLINK(mPoolHost)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mStyleSheetList)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mOlderShadow)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mYoungerShadow)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mAssociatedBinding)
tmp->mIdentifierMap.Clear();
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_UNLINK_END_INHERITED(DocumentFragment)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ShadowRoot)
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIContent)
@ -62,9 +54,10 @@ NS_IMPL_RELEASE_INHERITED(ShadowRoot, DocumentFragment)
ShadowRoot::ShadowRoot(Element* aElement,
already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
nsXBLPrototypeBinding* aProtoBinding)
: DocumentFragment(aNodeInfo), mPoolHost(aElement),
mProtoBinding(aProtoBinding), mShadowElement(nullptr),
mInsertionPointChanged(false), mIsComposedDocParticipant(false)
: DocumentFragment(aNodeInfo)
, mProtoBinding(aProtoBinding)
, mInsertionPointChanged(false)
, mIsComposedDocParticipant(false)
{
SetHost(aElement);
@ -81,23 +74,21 @@ ShadowRoot::ShadowRoot(Element* aElement,
// Add the ShadowRoot as a mutation observer on the host to watch
// for mutations because the insertion points in this ShadowRoot
// may need to be updated when the host children are modified.
mPoolHost->AddMutationObserver(this);
GetHost()->AddMutationObserver(this);
}
ShadowRoot::~ShadowRoot()
{
if (mPoolHost) {
if (GetHost()) {
// mPoolHost may have been unlinked or a new ShadowRoot may have been
// creating, making this one obsolete.
mPoolHost->RemoveMutationObserver(this);
GetHost()->RemoveMutationObserver(this);
}
UnsetFlags(NODE_IS_IN_SHADOW_TREE);
// nsINode destructor expects mSubtreeRoot == this.
SetSubtreeRootPointer(this);
SetHost(nullptr);
}
JSObject*
@ -243,15 +234,6 @@ ShadowRoot::RemoveInsertionPoint(HTMLContentElement* aInsertionPoint)
mInsertionPoints.RemoveElement(aInsertionPoint);
}
void
ShadowRoot::SetYoungerShadow(ShadowRoot* aYoungerShadow)
{
mYoungerShadow = aYoungerShadow;
mYoungerShadow->mOlderShadow = this;
ChangePoolHost(mYoungerShadow->GetShadowElement());
}
void
ShadowRoot::RemoveDestInsertionPoint(nsIContent* aInsertionPoint,
nsTArray<nsIContent*>& aDestInsertionPoints)
@ -300,8 +282,7 @@ ShadowRoot::DistributeSingleNode(nsIContent* aContent)
// Find the appropriate position in the matched node list for the
// newly distributed content.
bool isIndexFound = false;
MOZ_ASSERT(mPoolHost, "Where did the content come from if there is no pool host?");
ExplicitChildIterator childIterator(mPoolHost);
ExplicitChildIterator childIterator(GetHost());
for (uint32_t i = 0; i < matchedNodes.Length(); i++) {
// Seek through the host's explicit children until the inserted content
// is found or when the current matched node is reached.
@ -321,15 +302,6 @@ ShadowRoot::DistributeSingleNode(nsIContent* aContent)
insertionPoint->AppendMatchedNode(aContent);
}
// Handle the case where the parent of the insertion point is a ShadowRoot
// that is projected into the younger ShadowRoot's shadow insertion point.
// The node distributed into the insertion point must be reprojected
// to the shadow insertion point.
if (insertionPoint->GetParent() == this &&
mYoungerShadow && mYoungerShadow->GetShadowElement()) {
mYoungerShadow->GetShadowElement()->DistributeSingleNode(aContent);
}
// Handle the case where the parent of the insertion point has a ShadowRoot.
// The node distributed into the insertion point must be reprojected to the
// insertion points of the parent's ShadowRoot.
@ -337,16 +309,6 @@ ShadowRoot::DistributeSingleNode(nsIContent* aContent)
if (parentShadow) {
parentShadow->DistributeSingleNode(aContent);
}
// Handle the case where the parent of the insertion point is the <shadow>
// element. The node distributed into the insertion point must be reprojected
// into the older ShadowRoot's insertion points.
if (mShadowElement && mShadowElement == insertionPoint->GetParent()) {
ShadowRoot* olderShadow = mShadowElement->GetOlderShadowRoot();
if (olderShadow) {
olderShadow->DistributeSingleNode(aContent);
}
}
}
}
@ -368,15 +330,6 @@ ShadowRoot::RemoveDistributedNode(nsIContent* aContent)
mInsertionPoints[i]->RemoveMatchedNode(aContent);
// Handle the case where the parent of the insertion point is a ShadowRoot
// that is projected into the younger ShadowRoot's shadow insertion point.
// The removed node needs to be removed from the shadow insertion point.
if (mInsertionPoints[i]->GetParent() == this) {
if (mYoungerShadow && mYoungerShadow->GetShadowElement()) {
mYoungerShadow->GetShadowElement()->RemoveDistributedNode(aContent);
}
}
// Handle the case where the parent of the insertion point has a ShadowRoot.
// The removed node needs to be removed from the insertion points of the
// parent's ShadowRoot.
@ -385,16 +338,6 @@ ShadowRoot::RemoveDistributedNode(nsIContent* aContent)
parentShadow->RemoveDistributedNode(aContent);
}
// Handle the case where the parent of the insertion point is the <shadow>
// element. The removed node must be removed from the older ShadowRoot's
// insertion points.
if (mShadowElement && mShadowElement == mInsertionPoints[i]->GetParent()) {
ShadowRoot* olderShadow = mShadowElement->GetOlderShadowRoot();
if (olderShadow) {
olderShadow->RemoveDistributedNode(aContent);
}
}
break;
}
}
@ -405,16 +348,10 @@ ShadowRoot::DistributeAllNodes()
{
// Create node pool.
nsTArray<nsIContent*> nodePool;
// Make sure there is a pool host, an older shadow may not have
// one if the younger shadow does not have a <shadow> element.
if (mPoolHost) {
ExplicitChildIterator childIterator(mPoolHost);
for (nsIContent* content = childIterator.GetNextChild();
content;
content = childIterator.GetNextChild()) {
nodePool.AppendElement(content);
}
ExplicitChildIterator childIterator(GetHost());
for (nsIContent* content = childIterator.GetNextChild(); content;
content = childIterator.GetNextChild()) {
nodePool.AppendElement(content);
}
nsTArray<ShadowRoot*> shadowsToUpdate;
@ -445,20 +382,6 @@ ShadowRoot::DistributeAllNodes()
}
}
// If there is a shadow insertion point in this ShadowRoot, the children
// of the shadow insertion point needs to be distributed into the insertion
// points of the older ShadowRoot.
if (mShadowElement && mOlderShadow) {
mOlderShadow->DistributeAllNodes();
}
// If there is a younger ShadowRoot with a shadow insertion point,
// then the children of this ShadowRoot needs to be distributed to
// the younger ShadowRoot's shadow insertion point.
if (mYoungerShadow && mYoungerShadow->GetShadowElement()) {
mYoungerShadow->GetShadowElement()->DistributeAllNodes();
}
for (uint32_t i = 0; i < shadowsToUpdate.Length(); i++) {
shadowsToUpdate[i]->DistributeAllNodes();
}
@ -515,59 +438,6 @@ ShadowRoot::StyleSheets()
return mStyleSheetList;
}
void
ShadowRoot::SetShadowElement(HTMLShadowElement* aShadowElement)
{
// If there is already a shadow element point, remove
// the projected shadow because it is no longer an insertion
// point.
if (mShadowElement) {
mShadowElement->SetProjectedShadow(nullptr);
}
if (mOlderShadow) {
// Nodes for distribution will come from the new shadow element.
mOlderShadow->ChangePoolHost(aShadowElement);
}
// Set the new shadow element to project the older ShadowRoot because
// it is the current shadow insertion point.
mShadowElement = aShadowElement;
if (mShadowElement) {
mShadowElement->SetProjectedShadow(mOlderShadow);
}
}
void
ShadowRoot::ChangePoolHost(nsIContent* aNewHost)
{
if (mPoolHost) {
mPoolHost->RemoveMutationObserver(this);
}
// Clear the nodes matched to content insertion points
// because it is no longer relevant.
for (uint32_t i = 0; i < mInsertionPoints.Length(); i++) {
mInsertionPoints[i]->ClearMatchedNodes();
}
mPoolHost = aNewHost;
if (mPoolHost) {
mPoolHost->AddMutationObserver(this);
}
}
bool
ShadowRoot::IsShadowInsertionPoint(nsIContent* aContent)
{
if (!aContent) {
return false;
}
HTMLShadowElement* shadowElem = HTMLShadowElement::FromContent(aContent);
return shadowElem && shadowElem->IsInsertionPoint();
}
/**
* Returns whether the web components pool population algorithm
* on the host would contain |aContent|. This function ignores
@ -578,8 +448,7 @@ bool
ShadowRoot::IsPooledNode(nsIContent* aContent, nsIContent* aContainer,
nsIContent* aHost)
{
if (nsContentUtils::IsContentInsertionPoint(aContent) ||
IsShadowInsertionPoint(aContent)) {
if (nsContentUtils::IsContentInsertionPoint(aContent)) {
// Insertion points never end up in the pool.
return false;
}
@ -612,7 +481,7 @@ ShadowRoot::AttributeChanged(nsIDocument* aDocument,
int32_t aModType,
const nsAttrValue* aOldValue)
{
if (!IsPooledNode(aElement, aElement->GetParent(), mPoolHost)) {
if (!IsPooledNode(aElement, aElement->GetParent(), GetHost())) {
return;
}
@ -645,7 +514,7 @@ ShadowRoot::ContentAppended(nsIDocument* aDocument,
}
}
if (IsPooledNode(currentChild, aContainer, mPoolHost)) {
if (IsPooledNode(currentChild, aContainer, GetHost())) {
DistributeSingleNode(currentChild);
}
@ -667,7 +536,7 @@ ShadowRoot::ContentInserted(nsIDocument* aDocument,
// Watch for new nodes added to the pool because the node
// may need to be added to an insertion point.
if (IsPooledNode(aChild, aContainer, mPoolHost)) {
if (IsPooledNode(aChild, aContainer, GetHost())) {
// Add insertion point to destination insertion points of fallback content.
if (nsContentUtils::IsContentInsertionPoint(aContainer)) {
HTMLContentElement* content = HTMLContentElement::FromContent(aContainer);
@ -704,7 +573,7 @@ ShadowRoot::ContentRemoved(nsIDocument* aDocument,
// Watch for node that is removed from the pool because
// it may need to be removed from an insertion point.
if (IsPooledNode(aChild, aContainer, mPoolHost)) {
if (IsPooledNode(aChild, aContainer, GetHost())) {
RemoveDistributedNode(aChild);
}
}
@ -717,15 +586,6 @@ ShadowRoot::Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
return NS_ERROR_DOM_DATA_CLONE_ERR;
}
void
ShadowRoot::DestroyContent()
{
if (mOlderShadow) {
mOlderShadow->DestroyContent();
}
DocumentFragment::DestroyContent();
}
NS_IMPL_CYCLE_COLLECTION_INHERITED(ShadowRootStyleSheetList, StyleSheetList,
mShadowRoot)

Просмотреть файл

@ -25,7 +25,6 @@ namespace dom {
class Element;
class HTMLContentElement;
class HTMLShadowElement;
class ShadowRootStyleSheetList;
class ShadowRoot final : public DocumentFragment,
@ -42,7 +41,8 @@ public:
NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED
NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
ShadowRoot(Element* aElement, already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
ShadowRoot(Element* aElement,
already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
nsXBLPrototypeBinding* aProtoBinding);
void AddToIdTable(Element* aElement, nsIAtom* aId);
@ -52,24 +52,6 @@ public:
bool ApplyAuthorStyles();
void SetApplyAuthorStyles(bool aApplyAuthorStyles);
StyleSheetList* StyleSheets();
HTMLShadowElement* GetShadowElement() { return mShadowElement; }
/**
* Sets the current shadow insertion point where the older
* ShadowRoot will be projected.
*/
void SetShadowElement(HTMLShadowElement* aShadowElement);
/**
* Change the node that populates the distribution pool with
* its children. This is distinct from the ShadowRoot host described
* in the specifications. The ShadowRoot host is the element
* which created this ShadowRoot and does not change. The pool host
* is the same as the ShadowRoot host if this is the youngest
* ShadowRoot. If this is an older ShadowRoot, the pool host is
* the <shadow> element in the younger ShadowRoot (if it exists).
*/
void ChangePoolHost(nsIContent* aNewHost);
/**
* Distributes a single explicit child of the pool host to the content
@ -92,23 +74,15 @@ public:
void AddInsertionPoint(HTMLContentElement* aInsertionPoint);
void RemoveInsertionPoint(HTMLContentElement* aInsertionPoint);
void SetYoungerShadow(ShadowRoot* aYoungerShadow);
ShadowRoot* GetYoungerShadowRoot() { return mYoungerShadow; }
void SetInsertionPointChanged() { mInsertionPointChanged = true; }
void SetAssociatedBinding(nsXBLBinding* aBinding) { mAssociatedBinding = aBinding; }
nsISupports* GetParentObject() const { return mPoolHost; }
nsIContent* GetPoolHost() { return mPoolHost; }
nsTArray<HTMLShadowElement*>& ShadowDescendants() { return mShadowDescendants; }
JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
static bool IsPooledNode(nsIContent* aChild, nsIContent* aContainer,
nsIContent* aHost);
static ShadowRoot* FromNode(nsINode* aNode);
static bool IsShadowInsertionPoint(nsIContent* aContent);
static void RemoveDestInsertionPoint(nsIContent* aInsertionPoint,
nsTArray<nsIContent*>& aDestInsertionPoints);
@ -125,7 +99,6 @@ public:
void GetInnerHTML(nsAString& aInnerHTML);
void SetInnerHTML(const nsAString& aInnerHTML, ErrorResult& aError);
Element* Host();
ShadowRoot* GetOlderShadowRoot() { return mOlderShadow; }
void StyleSheetChanged();
bool IsComposedDocParticipant() { return mIsComposedDocParticipant; }
@ -134,14 +107,9 @@ public:
mIsComposedDocParticipant = aIsComposedDocParticipant;
}
virtual void DestroyContent() override;
protected:
virtual ~ShadowRoot();
// The pool host is the parent of the nodes that will be distributed
// into the insertion points in this ShadowRoot. See |ChangeShadowRoot|.
nsCOMPtr<nsIContent> mPoolHost;
// An array of content insertion points that are a descendant of the ShadowRoot
// sorted in tree order. Insertion points are responsible for notifying
// the ShadowRoot when they are removed or added as a descendant. The insertion
@ -149,10 +117,6 @@ protected:
// by the array.
nsTArray<HTMLContentElement*> mInsertionPoints;
// An array of the <shadow> elements that are descendant of the ShadowRoot
// sorted in tree order. Only the first may be a shadow insertion point.
nsTArray<HTMLShadowElement*> mShadowDescendants;
nsTHashtable<nsIdentifierMapEntry> mIdentifierMap;
nsXBLPrototypeBinding* mProtoBinding;
@ -163,17 +127,6 @@ protected:
RefPtr<ShadowRootStyleSheetList> mStyleSheetList;
// The current shadow insertion point of this ShadowRoot.
HTMLShadowElement* mShadowElement;
// The ShadowRoot that was created by the host element before
// this ShadowRoot was created.
RefPtr<ShadowRoot> mOlderShadow;
// The ShadowRoot that was created by the host element after
// this ShadowRoot was created.
RefPtr<ShadowRoot> mYoungerShadow;
// A boolean that indicates that an insertion point was added or removed
// from this ShadowRoot and that the nodes need to be redistributed into
// the insertion points. After this flag is set, nodes will be distributed

Просмотреть файл

@ -185,6 +185,7 @@ EXPORTS.mozilla.dom += [
'IdleRequest.h',
'ImageEncoder.h',
'ImageTracker.h',
'IntlUtils.h',
'Link.h',
'Location.h',
'NameSpaceConstants.h',
@ -258,6 +259,7 @@ UNIFIED_SOURCES += [
'IdleRequest.cpp',
'ImageEncoder.cpp',
'ImageTracker.cpp',
'IntlUtils.cpp',
'Link.cpp',
'Location.cpp',
'Navigator.cpp',
@ -375,14 +377,6 @@ if CONFIG['FUZZING']:
'FuzzingFunctions.cpp',
]
if CONFIG['ENABLE_INTL_API']:
UNIFIED_SOURCES += [
'IntlUtils.cpp',
]
EXPORTS.mozilla.dom += [
'IntlUtils.h',
]
# these files couldn't be in UNIFIED_SOURCES for now for reasons given below:
SOURCES += [
# Several conflicts with other bindings.

Просмотреть файл

@ -50,7 +50,6 @@
#include "mozilla/dom/HTMLInputElement.h"
#include "mozilla/dom/HTMLTemplateElement.h"
#include "mozilla/dom/HTMLContentElement.h"
#include "mozilla/dom/HTMLShadowElement.h"
#include "mozilla/dom/IPCBlobUtils.h"
#include "mozilla/dom/Promise.h"
#include "mozilla/dom/ScriptSettings.h"
@ -7567,20 +7566,6 @@ nsContentUtils::HasDistributedChildren(nsIContent* aContent)
return true;
}
ShadowRoot* shadow = ShadowRoot::FromNode(aContent);
if (shadow) {
// Children of a shadow root are distributed to
// the shadow insertion point of the younger shadow root.
return shadow->GetYoungerShadowRoot();
}
HTMLShadowElement* shadowEl = HTMLShadowElement::FromContent(aContent);
if (shadowEl && shadowEl->IsInsertionPoint()) {
// Children of a shadow insertion points are distributed
// to the insertion points in the older shadow root.
return shadowEl->GetOlderShadowRoot();
}
HTMLContentElement* contentEl = HTMLContentElement::FromContent(aContent);
if (contentEl && contentEl->IsInsertionPoint()) {
// Children of a content insertion point are distributed to the
@ -10154,6 +10139,49 @@ nsContentUtils::GetElementDefinitionIfObservingAttr(Element* aCustomElement,
return definition;
}
/* static */ void
nsContentUtils::SyncInvokeReactions(nsIDocument::ElementCallbackType aType,
Element* aElement,
CustomElementDefinition* aDefinition)
{
MOZ_ASSERT(aElement);
nsIDocument* doc = aElement->OwnerDoc();
nsPIDOMWindowInner* window(doc->GetInnerWindow());
if (!window) {
return;
}
RefPtr<CustomElementRegistry> registry(window->CustomElements());
if (!registry) {
return;
}
registry->SyncInvokeReactions(aType, aElement, aDefinition);
}
/* static */ void
nsContentUtils::EnqueueUpgradeReaction(Element* aElement,
CustomElementDefinition* aDefinition)
{
MOZ_ASSERT(aElement);
nsIDocument* doc = aElement->OwnerDoc();
nsPIDOMWindowInner* window(doc->GetInnerWindow());
if (!window) {
return;
}
RefPtr<CustomElementRegistry> registry(window->CustomElements());
if (!registry) {
return;
}
CustomElementReactionsStack* stack =
doc->GetDocGroup()->CustomElementReactionsStack();
stack->EnqueueUpgradeReaction(registry, aElement, aDefinition);
}
/* static */ void
nsContentUtils::EnqueueLifecycleCallback(nsIDocument* aDoc,
nsIDocument::ElementCallbackType aType,

Просмотреть файл

@ -2998,6 +2998,13 @@ public:
nsIAtom* aExtensionType,
nsIAtom* aAttrName);
static void SyncInvokeReactions(nsIDocument::ElementCallbackType aType,
Element* aCustomElement,
mozilla::dom::CustomElementDefinition* aDefinition);
static void EnqueueUpgradeReaction(Element* aElement,
mozilla::dom::CustomElementDefinition* aDefinition);
static void EnqueueLifecycleCallback(nsIDocument* aDoc,
nsIDocument::ElementCallbackType aType,
Element* aCustomElement,

Просмотреть файл

@ -279,6 +279,7 @@
#include "mozilla/DocumentStyleRootIterator.h"
#include "mozilla/ServoRestyleManager.h"
#include "mozilla/ClearOnShutdown.h"
#include "nsHTMLTags.h"
using namespace mozilla;
using namespace mozilla::dom;
@ -6024,6 +6025,10 @@ nsDocument::CreateElement(const nsAString& aTagName,
elem->SetPseudoElementType(pseudoType);
}
if (is) {
elem->SetAttr(kNameSpaceID_None, nsGkAtoms::is, *is, true);
}
return elem.forget();
}
@ -6075,6 +6080,10 @@ nsDocument::CreateElementNS(const nsAString& aNamespaceURI,
return nullptr;
}
if (is) {
element->SetAttr(kNameSpaceID_None, nsGkAtoms::is, *is, true);
}
return element.forget();
}
@ -6357,11 +6366,26 @@ nsDocument::CustomElementConstructor(JSContext* aCx, unsigned aArgc, JS::Value*
return true;
}
} else {
nsDependentAtomString localName(definition->mLocalName);
element =
document->CreateElem(localName, nullptr, kNameSpaceID_XHTML,
(definition->mLocalName != typeAtom) ? &elemName
: nullptr);
RefPtr<mozilla::dom::NodeInfo> nodeInfo =
document->NodeInfoManager()->GetNodeInfo(definition->mLocalName, nullptr,
kNameSpaceID_XHTML,
nsIDOMNode::ELEMENT_NODE);
int32_t tag = nsHTMLTags::CaseSensitiveAtomTagToId(definition->mLocalName);
if (tag == eHTMLTag_userdefined &&
nsContentUtils::IsCustomElementName(definition->mType)) {
element = NS_NewHTMLElement(nodeInfo.forget(), NOT_FROM_PARSER);
} else {
element = ::CreateHTMLElement(tag, nodeInfo.forget(), NOT_FROM_PARSER);
}
element->SetCustomElementData(
new CustomElementData(definition->mType,
CustomElementData::State::eCustom));
// It'll be removed when we deprecate custom elements v0.
nsContentUtils::SyncInvokeReactions(nsIDocument::eCreated, element,
definition);
NS_ENSURE_TRUE(element, false);
}

Просмотреть файл

@ -1660,7 +1660,6 @@ GK_ATOM(saturate, "saturate")
GK_ATOM(saturation, "saturation")
GK_ATOM(set, "set")
GK_ATOM(seed, "seed")
GK_ATOM(shadow, "shadow")
GK_ATOM(shape_rendering, "shape-rendering")
GK_ATOM(skewX, "skewX")
GK_ATOM(skewY, "skewY")

Просмотреть файл

@ -233,9 +233,7 @@
#include "mozilla/dom/Fetch.h"
#include "mozilla/dom/FunctionBinding.h"
#include "mozilla/dom/HashChangeEvent.h"
#ifdef ENABLE_INTL_API
#include "mozilla/dom/IntlUtils.h"
#endif
#include "mozilla/dom/MozSelfSupportBinding.h"
#include "mozilla/dom/PopStateEvent.h"
#include "mozilla/dom/PopupBlockedEvent.h"
@ -2065,9 +2063,7 @@ nsGlobalWindow::CleanUp()
mServiceWorkerRegistrationTable.Clear();
#ifdef ENABLE_INTL_API
mIntlUtils = nullptr;
#endif
}
void
@ -2356,9 +2352,7 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(nsGlobalWindow)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPaintWorklet)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mExternal)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMozSelfSupport)
#ifdef ENABLE_INTL_API
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIntlUtils)
#endif
tmp->TraverseHostObjectURIs(cb);
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
@ -2436,9 +2430,7 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsGlobalWindow)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mPaintWorklet)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mExternal)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mMozSelfSupport)
#ifdef ENABLE_INTL_API
NS_IMPL_CYCLE_COLLECTION_UNLINK(mIntlUtils)
#endif
tmp->UnlinkHostObjectURIs();
@ -15091,7 +15083,6 @@ nsGlobalWindow::GetRegionalPrefsLocales(nsTArray<nsString>& aLocales)
}
}
#ifdef ENABLE_INTL_API
IntlUtils*
nsGlobalWindow::GetIntlUtils(ErrorResult& aError)
{
@ -15103,7 +15094,6 @@ nsGlobalWindow::GetIntlUtils(ErrorResult& aError)
return mIntlUtils;
}
#endif
template class nsPIDOMWindow<mozIDOMWindowProxy>;
template class nsPIDOMWindow<mozIDOMWindow>;

Просмотреть файл

@ -123,9 +123,7 @@ enum class ImageBitmapFormat : uint8_t;
class IdleRequest;
class IdleRequestCallback;
class IncrementalRunnable;
#ifdef ENABLE_INTL_API
class IntlUtils;
#endif
class Location;
class MediaQueryList;
class MozSelfSupport;
@ -959,10 +957,8 @@ public:
void
GetRegionalPrefsLocales(nsTArray<nsString>& aLocales);
#ifdef ENABLE_INTL_API
mozilla::dom::IntlUtils*
GetIntlUtils(mozilla::ErrorResult& aRv);
#endif
protected:
bool AlertOrConfirm(bool aAlert, const nsAString& aMessage,
@ -2027,9 +2023,7 @@ protected:
uint32_t mAutoActivateVRDisplayID; // Outer windows only
int64_t mBeforeUnloadListenerCount; // Inner windows only
#ifdef ENABLE_INTL_API
RefPtr<mozilla::dom::IntlUtils> mIntlUtils;
#endif
friend class nsDOMScriptableHelper;
friend class nsDOMWindowUtils;

Просмотреть файл

@ -66,7 +66,7 @@ using mozilla::AutoJSContext;
} \
ShadowRoot* shadow = ShadowRoot::FromNode(node); \
if (shadow) { \
node = shadow->GetPoolHost(); \
node = shadow->GetHost(); \
} else { \
node = node->GetParentNode(); \
} \
@ -94,7 +94,7 @@ using mozilla::AutoJSContext;
} \
ShadowRoot* shadow = ShadowRoot::FromNode(node); \
if (shadow) { \
node = shadow->GetPoolHost(); \
node = shadow->GetHost(); \
} else { \
node = node->GetParentNode(); \
} \

Просмотреть файл

@ -587,7 +587,7 @@ function testOutsideShadowDOM() {
is(records.length, 1);
is(records[0].type, "attributes", "Should have got attributes");
observer.disconnect();
then(testInsideShadowDOM);
then(testMarquee);
});
m.observe(div, {
attributes: true,
@ -603,32 +603,6 @@ function testOutsideShadowDOM() {
div.setAttribute("foo", "bar");
}
function testInsideShadowDOM() {
var m = new M(function(records, observer) {
is(records.length, 4);
is(records[0].type, "childList");
is(records[1].type, "attributes");
is(records[2].type, "characterData");
is(records[3].type, "childList");
observer.disconnect();
then(testMarquee);
});
var sr = div.createShadowRoot();
m.observe(sr, {
attributes: true,
childList: true,
characterData: true,
subtree: true
});
sr.innerHTML = "<div" + ">text</" + "div>";
sr.firstChild.setAttribute("foo", "bar");
sr.firstChild.firstChild.data = "text2";
sr.firstChild.appendChild(document.createElement("div"));
div.setAttribute("foo", "bar2");
}
function testMarquee() {
var m = new M(function(records, observer) {
is(records.length, 1);

11
dom/cache/CacheStreamControlChild.cpp поставляемый
Просмотреть файл

@ -115,11 +115,18 @@ CacheStreamControlChild::OpenStream(const nsID& aId, InputStreamResolver&& aReso
return;
}
// If we are on a worker, then we need to hold it alive until the async
// IPC operation below completes. While the IPC layer will trigger a
// rejection here in many cases, we must handle the case where the
// MozPromise resolve runnable is already in the event queue when the
// worker wants to shut down.
RefPtr<CacheWorkerHolder> holder = GetWorkerHolder();
SendOpenStream(aId)->Then(GetCurrentThreadSerialEventTarget(), __func__,
[aResolver](const OptionalIPCStream& aOptionalStream) {
[aResolver, holder](const OptionalIPCStream& aOptionalStream) {
nsCOMPtr<nsIInputStream> stream = DeserializeIPCStream(aOptionalStream);
aResolver(Move(stream));
}, [aResolver](PromiseRejectReason aReason) {
}, [aResolver, holder](PromiseRejectReason aReason) {
aResolver(nullptr);
});
}

Просмотреть файл

@ -0,0 +1,9 @@
<canvas id='canv'></canvas>
<script>
var ctx=document.getElementById('canv').getContext('2d');
ctx.globalAlpha=0.81;
ctx.scale(22,3406781);
ctx.filter='sepia(80%)';
ctx.font='52px serif';
ctx.measureText('A');
</script>

Просмотреть файл

@ -37,6 +37,7 @@ load 1288872-1.html
load 1290628-1.html
load 1283113-1.html
load 1286458-1.html
load 1296410-1.html
load 1299062-1.html
load 1305085-1.html
load 1305312-1.html

Просмотреть файл

@ -79,7 +79,7 @@ skip-if = toolkit == 'android'
[test_bug605242.html]
skip-if = toolkit == 'android' #CRASH_DUMP, RANDOM
[test_bug607464.html]
skip-if = toolkit == 'android' || (e10s && os == 'win') || (e10s && os == "mac") #CRASH_DUMP, RANDOM, bug 1252273
skip-if = toolkit == 'android' || e10s #CRASH_DUMP, RANDOM, bug 1252273, bug 1400586
[test_bug613634.html]
skip-if = toolkit == 'android' #CRASH_DUMP, RANDOM
[test_bug615597.html]

Просмотреть файл

@ -1,373 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/dom/ShadowRoot.h"
#include "ChildIterator.h"
#include "nsContentUtils.h"
#include "nsDocument.h"
#include "mozilla/dom/HTMLShadowElement.h"
#include "mozilla/dom/HTMLUnknownElement.h"
#include "mozilla/dom/HTMLShadowElementBinding.h"
// Expand NS_IMPL_NS_NEW_HTML_ELEMENT(Shadow) to add check for web components
// being enabled.
nsGenericHTMLElement*
NS_NewHTMLShadowElement(already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
mozilla::dom::FromParser aFromParser)
{
// When this check is removed, remove the nsDocument.h and
// HTMLUnknownElement.h includes. Also remove nsINode::IsHTMLShadowElement.
//
// We have to jump through some hoops to be able to produce both NodeInfo* and
// already_AddRefed<NodeInfo>& for our callees.
RefPtr<mozilla::dom::NodeInfo> nodeInfo(aNodeInfo);
if (!nsDocument::IsWebComponentsEnabled(nodeInfo)) {
already_AddRefed<mozilla::dom::NodeInfo> nodeInfoArg(nodeInfo.forget());
return new mozilla::dom::HTMLUnknownElement(nodeInfoArg);
}
already_AddRefed<mozilla::dom::NodeInfo> nodeInfoArg(nodeInfo.forget());
return new mozilla::dom::HTMLShadowElement(nodeInfoArg);
}
using namespace mozilla::dom;
HTMLShadowElement::HTMLShadowElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo)
: nsGenericHTMLElement(aNodeInfo), mIsInsertionPoint(false)
{
}
HTMLShadowElement::~HTMLShadowElement()
{
if (mProjectedShadow) {
mProjectedShadow->RemoveMutationObserver(this);
}
}
NS_IMPL_CYCLE_COLLECTION_CLASS(HTMLShadowElement)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(HTMLShadowElement,
nsGenericHTMLElement)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mProjectedShadow)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(HTMLShadowElement,
nsGenericHTMLElement)
if (tmp->mProjectedShadow) {
tmp->mProjectedShadow->RemoveMutationObserver(tmp);
tmp->mProjectedShadow = nullptr;
}
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_ADDREF_INHERITED(HTMLShadowElement, Element)
NS_IMPL_RELEASE_INHERITED(HTMLShadowElement, Element)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(HTMLShadowElement)
NS_INTERFACE_MAP_END_INHERITING(nsGenericHTMLElement)
NS_IMPL_ELEMENT_CLONE(HTMLShadowElement)
JSObject*
HTMLShadowElement::WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto)
{
return HTMLShadowElementBinding::Wrap(aCx, this, aGivenProto);
}
void
HTMLShadowElement::SetProjectedShadow(ShadowRoot* aProjectedShadow)
{
if (mProjectedShadow) {
mProjectedShadow->RemoveMutationObserver(this);
// The currently projected ShadowRoot is going away,
// thus the destination insertion points need to be updated.
ExplicitChildIterator childIterator(mProjectedShadow);
for (nsIContent* content = childIterator.GetNextChild();
content;
content = childIterator.GetNextChild()) {
ShadowRoot::RemoveDestInsertionPoint(this, content->DestInsertionPoints());
}
}
mProjectedShadow = aProjectedShadow;
if (mProjectedShadow) {
// A new ShadowRoot is being projected, thus its explcit
// children will be distributed to this shadow insertion point.
ExplicitChildIterator childIterator(mProjectedShadow);
for (nsIContent* content = childIterator.GetNextChild();
content;
content = childIterator.GetNextChild()) {
content->DestInsertionPoints().AppendElement(this);
}
// Watch for mutations on the projected shadow because
// it affects the nodes that are distributed to this shadow
// insertion point.
mProjectedShadow->AddMutationObserver(this);
}
}
static bool
IsInFallbackContent(nsIContent* aContent)
{
nsINode* parentNode = aContent->GetParentNode();
while (parentNode) {
if (parentNode->IsHTMLElement(nsGkAtoms::content)) {
return true;
}
parentNode = parentNode->GetParentNode();
}
return false;
}
nsresult
HTMLShadowElement::BindToTree(nsIDocument* aDocument,
nsIContent* aParent,
nsIContent* aBindingParent,
bool aCompileEventHandlers)
{
RefPtr<ShadowRoot> oldContainingShadow = GetContainingShadow();
nsresult rv = nsGenericHTMLElement::BindToTree(aDocument, aParent,
aBindingParent,
aCompileEventHandlers);
NS_ENSURE_SUCCESS(rv, rv);
ShadowRoot* containingShadow = GetContainingShadow();
if (containingShadow && !oldContainingShadow) {
// Keep track of all descendant <shadow> elements in tree order so
// that when the current shadow insertion point is removed, the next
// one can be found quickly.
TreeOrderComparator comparator;
containingShadow->ShadowDescendants().InsertElementSorted(this, comparator);
if (containingShadow->ShadowDescendants()[0] != this) {
// Only the first <shadow> (in tree order) of a ShadowRoot can be an insertion point.
return NS_OK;
}
if (IsInFallbackContent(this)) {
// If the first shadow element in tree order is invalid (in fallback content),
// the containing ShadowRoot will not have a shadow insertion point.
containingShadow->SetShadowElement(nullptr);
} else {
mIsInsertionPoint = true;
containingShadow->SetShadowElement(this);
}
containingShadow->SetInsertionPointChanged();
}
if (mIsInsertionPoint && containingShadow) {
// Propagate BindToTree calls to projected shadow root children.
ShadowRoot* projectedShadow = containingShadow->GetOlderShadowRoot();
if (projectedShadow) {
projectedShadow->SetIsComposedDocParticipant(IsInComposedDoc());
for (nsIContent* child = projectedShadow->GetFirstChild(); child;
child = child->GetNextSibling()) {
rv = child->BindToTree(nullptr, projectedShadow,
projectedShadow->GetBindingParent(),
aCompileEventHandlers);
NS_ENSURE_SUCCESS(rv, rv);
}
}
}
return NS_OK;
}
void
HTMLShadowElement::UnbindFromTree(bool aDeep, bool aNullParent)
{
RefPtr<ShadowRoot> oldContainingShadow = GetContainingShadow();
if (mIsInsertionPoint && oldContainingShadow) {
// Propagate UnbindFromTree call to previous projected shadow
// root children.
ShadowRoot* projectedShadow = oldContainingShadow->GetOlderShadowRoot();
if (projectedShadow) {
for (nsIContent* child = projectedShadow->GetFirstChild(); child;
child = child->GetNextSibling()) {
child->UnbindFromTree(true, false);
}
projectedShadow->SetIsComposedDocParticipant(false);
}
}
nsGenericHTMLElement::UnbindFromTree(aDeep, aNullParent);
if (oldContainingShadow && !GetContainingShadow() && mIsInsertionPoint) {
nsTArray<HTMLShadowElement*>& shadowDescendants =
oldContainingShadow->ShadowDescendants();
shadowDescendants.RemoveElement(this);
oldContainingShadow->SetShadowElement(nullptr);
// Find the next shadow insertion point.
if (shadowDescendants.Length() > 0 &&
!IsInFallbackContent(shadowDescendants[0])) {
oldContainingShadow->SetShadowElement(shadowDescendants[0]);
}
oldContainingShadow->SetInsertionPointChanged();
mIsInsertionPoint = false;
}
}
void
HTMLShadowElement::DistributeSingleNode(nsIContent* aContent)
{
if (aContent->DestInsertionPoints().Contains(this)) {
// Node has already been distrbuted this this node,
// we are done.
return;
}
aContent->DestInsertionPoints().AppendElement(this);
// Handle the case where the shadow element is a child of
// a node with a ShadowRoot. The nodes that have been distributed to
// this shadow insertion point will need to be reprojected into the
// insertion points of the parent's ShadowRoot.
ShadowRoot* parentShadowRoot = GetParent()->GetShadowRoot();
if (parentShadowRoot) {
parentShadowRoot->DistributeSingleNode(aContent);
return;
}
// Handle the case where the parent of this shadow element is a ShadowRoot
// that is projected into a shadow insertion point in the younger ShadowRoot.
ShadowRoot* containingShadow = GetContainingShadow();
ShadowRoot* youngerShadow = containingShadow->GetYoungerShadowRoot();
if (youngerShadow && GetParent() == containingShadow) {
HTMLShadowElement* youngerShadowElement = youngerShadow->GetShadowElement();
if (youngerShadowElement) {
youngerShadowElement->DistributeSingleNode(aContent);
}
}
}
void
HTMLShadowElement::RemoveDistributedNode(nsIContent* aContent)
{
ShadowRoot::RemoveDestInsertionPoint(this, aContent->DestInsertionPoints());
// Handle the case where the shadow element is a child of
// a node with a ShadowRoot. The nodes that have been distributed to
// this shadow insertion point will need to be removed from the
// insertion points of the parent's ShadowRoot.
ShadowRoot* parentShadowRoot = GetParent()->GetShadowRoot();
if (parentShadowRoot) {
parentShadowRoot->RemoveDistributedNode(aContent);
return;
}
// Handle the case where the parent of this shadow element is a ShadowRoot
// that is projected into a shadow insertion point in the younger ShadowRoot.
ShadowRoot* containingShadow = GetContainingShadow();
ShadowRoot* youngerShadow = containingShadow->GetYoungerShadowRoot();
if (youngerShadow && GetParent() == containingShadow) {
HTMLShadowElement* youngerShadowElement = youngerShadow->GetShadowElement();
if (youngerShadowElement) {
youngerShadowElement->RemoveDistributedNode(aContent);
}
}
}
void
HTMLShadowElement::DistributeAllNodes()
{
// All the explicit children of the projected ShadowRoot are distributed
// into this shadow insertion point so update the destination insertion
// points.
ShadowRoot* containingShadow = GetContainingShadow();
ShadowRoot* olderShadow = containingShadow->GetOlderShadowRoot();
if (olderShadow) {
ExplicitChildIterator childIterator(olderShadow);
for (nsIContent* content = childIterator.GetNextChild();
content;
content = childIterator.GetNextChild()) {
ShadowRoot::RemoveDestInsertionPoint(this, content->DestInsertionPoints());
content->DestInsertionPoints().AppendElement(this);
}
}
// Handle the case where the shadow element is a child of
// a node with a ShadowRoot. The nodes that have been distributed to
// this shadow insertion point will need to be reprojected into the
// insertion points of the parent's ShadowRoot.
ShadowRoot* parentShadowRoot = GetParent()->GetShadowRoot();
if (parentShadowRoot) {
parentShadowRoot->DistributeAllNodes();
return;
}
// Handle the case where the parent of this shadow element is a ShadowRoot
// that is projected into a shadow insertion point in the younger ShadowRoot.
ShadowRoot* youngerShadow = containingShadow->GetYoungerShadowRoot();
if (youngerShadow && GetParent() == containingShadow) {
HTMLShadowElement* youngerShadowElement = youngerShadow->GetShadowElement();
if (youngerShadowElement) {
youngerShadowElement->DistributeAllNodes();
}
}
}
void
HTMLShadowElement::ContentAppended(nsIDocument* aDocument,
nsIContent* aContainer,
nsIContent* aFirstNewContent,
int32_t aNewIndexInContainer)
{
// Watch for content appended to the projected shadow (the ShadowRoot that
// will be rendered in place of this shadow insertion point) because the
// nodes may need to be distributed into other insertion points.
nsIContent* currentChild = aFirstNewContent;
while (currentChild) {
if (ShadowRoot::IsPooledNode(currentChild, aContainer, mProjectedShadow)) {
DistributeSingleNode(currentChild);
}
currentChild = currentChild->GetNextSibling();
}
}
void
HTMLShadowElement::ContentInserted(nsIDocument* aDocument,
nsIContent* aContainer,
nsIContent* aChild,
int32_t aIndexInContainer)
{
// Watch for content appended to the projected shadow (the ShadowRoot that
// will be rendered in place of this shadow insertion point) because the
// nodes may need to be distributed into other insertion points.
if (!ShadowRoot::IsPooledNode(aChild, aContainer, mProjectedShadow)) {
return;
}
DistributeSingleNode(aChild);
}
void
HTMLShadowElement::ContentRemoved(nsIDocument* aDocument,
nsIContent* aContainer,
nsIContent* aChild,
int32_t aIndexInContainer,
nsIContent* aPreviousSibling)
{
// Watch for content removed from the projected shadow (the ShadowRoot that
// will be rendered in place of this shadow insertion point) because the
// nodes may need to be removed from other insertion points.
if (!ShadowRoot::IsPooledNode(aChild, aContainer, mProjectedShadow)) {
return;
}
RemoveDistributedNode(aChild);
}

Просмотреть файл

@ -1,97 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_dom_HTMLShadowElement_h__
#define mozilla_dom_HTMLShadowElement_h__
#include "nsGenericHTMLElement.h"
namespace mozilla {
namespace dom {
class HTMLShadowElement final : public nsGenericHTMLElement,
public nsStubMutationObserver
{
public:
explicit HTMLShadowElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo);
// nsISupports
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED
NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED
NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(HTMLShadowElement,
nsGenericHTMLElement)
static HTMLShadowElement* FromContent(nsIContent* aContent)
{
if (aContent->IsHTMLShadowElement()) {
return static_cast<HTMLShadowElement*>(aContent);
}
return nullptr;
}
virtual bool IsHTMLShadowElement() const override { return true; }
virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
bool aPreallocateChildren) const override;
virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
nsIContent* aBindingParent,
bool aCompileEventHandlers) override;
virtual void UnbindFromTree(bool aDeep = true,
bool aNullParent = true) override;
bool IsInsertionPoint() { return mIsInsertionPoint; }
/**
* Sets the ShadowRoot that will be rendered in place of
* this shadow insertion point.
*/
void SetProjectedShadow(ShadowRoot* aProjectedShadow);
/**
* Distributes a single explicit child of the projected ShadowRoot
* to relevant insertion points.
*/
void DistributeSingleNode(nsIContent* aContent);
/**
* Removes a single explicit child of the projected ShadowRoot
* from relevant insertion points.
*/
void RemoveDistributedNode(nsIContent* aContent);
/**
* Distributes all the explicit children of the projected ShadowRoot
* to the shadow insertion point in the younger ShadowRoot and
* the content insertion point of the parent node's ShadowRoot.
*/
void DistributeAllNodes();
// WebIDL methods.
ShadowRoot* GetOlderShadowRoot() { return mProjectedShadow; }
protected:
virtual ~HTMLShadowElement();
virtual JSObject* WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto) override;
// The ShadowRoot that will be rendered in place of this shadow insertion point.
RefPtr<ShadowRoot> mProjectedShadow;
bool mIsInsertionPoint;
};
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_HTMLShadowElement_h__

Просмотреть файл

@ -95,7 +95,6 @@ EXPORTS.mozilla.dom += [
'HTMLProgressElement.h',
'HTMLScriptElement.h',
'HTMLSelectElement.h',
'HTMLShadowElement.h',
'HTMLSharedElement.h',
'HTMLSharedListElement.h',
'HTMLSourceElement.h',
@ -175,7 +174,6 @@ UNIFIED_SOURCES += [
'HTMLProgressElement.cpp',
'HTMLScriptElement.cpp',
'HTMLSelectElement.cpp',
'HTMLShadowElement.cpp',
'HTMLSharedElement.cpp',
'HTMLSharedListElement.cpp',
'HTMLSourceElement.cpp',

Просмотреть файл

@ -1581,7 +1581,6 @@ NS_DECLARE_NS_NEW_HTML_ELEMENT(Pre)
NS_DECLARE_NS_NEW_HTML_ELEMENT(Progress)
NS_DECLARE_NS_NEW_HTML_ELEMENT(Script)
NS_DECLARE_NS_NEW_HTML_ELEMENT(Select)
NS_DECLARE_NS_NEW_HTML_ELEMENT(Shadow)
NS_DECLARE_NS_NEW_HTML_ELEMENT(Source)
NS_DECLARE_NS_NEW_HTML_ELEMENT(Span)
NS_DECLARE_NS_NEW_HTML_ELEMENT(Style)

Просмотреть файл

@ -24,6 +24,7 @@
#include "nsServiceManagerUtils.h"
#include "nsSubDocumentFrame.h"
#include "nsXULElement.h"
#include "nsAttrValueOrString.h"
using namespace mozilla;
using namespace mozilla::dom;

Просмотреть файл

@ -30,6 +30,7 @@
#include "mozilla/Logging.h"
#include "nsNodeUtils.h"
#include "nsIContent.h"
#include "mozilla/dom/CustomElementRegistry.h"
#include "mozilla/dom/Element.h"
#include "mozilla/Preferences.h"
@ -223,6 +224,26 @@ public:
int32_t mStackPos;
};
static void
DoCustomElementCreate(Element** aElement, nsIDocument* aDoc,
CustomElementConstructor* aConstructor, ErrorResult& aRv)
{
RefPtr<Element> element =
aConstructor->Construct("Custom Element Create", aRv);
if (aRv.Failed() || !element->IsHTMLElement()) {
aRv.ThrowTypeError<MSG_THIS_DOES_NOT_IMPLEMENT_INTERFACE>(NS_LITERAL_STRING("HTMLElement"));
return;
}
if (aDoc != element->OwnerDoc() || element->GetParentNode() ||
element->HasChildren() || element->GetAttrCount()) {
aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
return;
}
element.forget(aElement);
}
nsresult
NS_NewHTMLElement(Element** aResult, already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
FromParser aFromParser, const nsAString* aIs)
@ -238,6 +259,81 @@ NS_NewHTMLElement(Element** aResult, already_AddRefed<mozilla::dom::NodeInfo>&&
int32_t tag = nsHTMLTags::CaseSensitiveAtomTagToId(name);
// https://dom.spec.whatwg.org/#concept-create-element
// We only handle the "synchronous custom elements flag is set" now.
// For the unset case (e.g. cloning a node), see bug 1319342 for that.
// Step 4.
CustomElementDefinition* definition = nullptr;
if (CustomElementRegistry::IsCustomElementEnabled()) {
definition =
nsContentUtils::LookupCustomElementDefinition(nodeInfo->GetDocument(),
nodeInfo->LocalName(),
nodeInfo->NamespaceID(),
aIs);
}
// It might be a problem that parser synchronously calls constructor, so filed
// bug 1378079 to figure out what we should do for parser case.
if (definition) {
/*
* Synchronous custom elements flag is determined by 3 places in spec,
* 1) create an element for a token, the flag is determined by
* "will execute script" which is not originally created
* for the HTML fragment parsing algorithm.
* 2) createElement and createElementNS, the flag is the same as
* NOT_FROM_PARSER.
* 3) clone a node, our implementation will not go into this function.
* For the unset case which is non-synchronous only applied for
* inner/outerHTML.
*/
bool synchronousCustomElements = aFromParser != dom::FROM_PARSER_FRAGMENT ||
aFromParser == dom::NOT_FROM_PARSER;
// Per discussion in https://github.com/w3c/webcomponents/issues/635,
// use entry global in those places that are called from JS APIs.
nsIGlobalObject* global = GetEntryGlobal();
MOZ_ASSERT(global);
AutoEntryScript aes(global, "create custom elements");
JSContext* cx = aes.cx();
ErrorResult rv;
// Step 5.
if (definition->IsCustomBuiltIn()) {
// SetupCustomElement() should be called with an element that don't have
// CustomElementData setup, if not we will hit the assertion in
// SetCustomElementData().
nsCOMPtr<nsIAtom> tagAtom = nodeInfo->NameAtom();
nsCOMPtr<nsIAtom> typeAtom = aIs ? NS_Atomize(*aIs) : tagAtom;
// Built-in element
*aResult = CreateHTMLElement(tag, nodeInfo.forget(), aFromParser).take();
(*aResult)->SetCustomElementData(new CustomElementData(typeAtom));
if (synchronousCustomElements) {
CustomElementRegistry::Upgrade(*aResult, definition, rv);
} else {
nsContentUtils::EnqueueUpgradeReaction(*aResult, definition);
}
if (rv.MaybeSetPendingException(cx)) {
aes.ReportException();
}
return NS_OK;
}
// Step 6.1.
if (synchronousCustomElements) {
DoCustomElementCreate(aResult, nodeInfo->GetDocument(),
definition->mConstructor, rv);
if (rv.MaybeSetPendingException(cx)) {
NS_IF_ADDREF(*aResult = NS_NewHTMLUnknownElement(nodeInfo.forget(), aFromParser));
}
return NS_OK;
}
// Step 6.2.
NS_IF_ADDREF(*aResult = NS_NewHTMLElement(nodeInfo.forget(), aFromParser));
nsContentUtils::EnqueueUpgradeReaction(*aResult, definition);
return NS_OK;
}
// Per the Custom Element specification, unknown tags that are valid custom
// element names should be HTMLElement instead of HTMLUnknownElement.
bool isCustomElementName = (tag == eHTMLTag_userdefined &&

Просмотреть файл

@ -7715,12 +7715,10 @@ private:
void
SendResults() override;
#ifdef ENABLE_INTL_API
static nsresult
UpdateLocaleAwareIndex(mozIStorageConnection* aConnection,
const IndexMetadata& aIndexMetadata,
const nsCString& aLocale);
#endif
};
class OpenDatabaseOp::VersionChangeOp final
@ -19914,9 +19912,6 @@ DatabaseOperationBase::BindKeyRangeToStatement(
mozIStorageStatement* aStatement,
const nsCString& aLocale)
{
#ifndef ENABLE_INTL_API
return BindKeyRangeToStatement(aKeyRange, aStatement);
#else
MOZ_ASSERT(!IsOnBackgroundThread());
MOZ_ASSERT(aStatement);
MOZ_ASSERT(!aLocale.IsEmpty());
@ -19954,7 +19949,6 @@ DatabaseOperationBase::BindKeyRangeToStatement(
}
return NS_OK;
#endif
}
// static
@ -22017,7 +22011,6 @@ OpenDatabaseOp::LoadDatabaseInformation(mozIStorageConnection* aConnection)
indexMetadata->mCommonMetadata.multiEntry() = !!scratch;
#ifdef ENABLE_INTL_API
const bool localeAware = !stmt->IsNull(6);
if (localeAware) {
rv = stmt->GetUTF8String(6, indexMetadata->mCommonMetadata.locale());
@ -22047,7 +22040,6 @@ OpenDatabaseOp::LoadDatabaseInformation(mozIStorageConnection* aConnection)
}
}
}
#endif
if (NS_WARN_IF(!objectStoreMetadata->mIndexes.Put(indexId, indexMetadata,
fallible))) {
@ -22073,7 +22065,6 @@ OpenDatabaseOp::LoadDatabaseInformation(mozIStorageConnection* aConnection)
return NS_OK;
}
#ifdef ENABLE_INTL_API
/* static */
nsresult
OpenDatabaseOp::UpdateLocaleAwareIndex(mozIStorageConnection* aConnection,
@ -22191,7 +22182,6 @@ OpenDatabaseOp::UpdateLocaleAwareIndex(mozIStorageConnection* aConnection,
rv = metaStmt->Execute();
return rv;
}
#endif
nsresult
OpenDatabaseOp::BeginVersionChange()
@ -27966,15 +27956,12 @@ OpenOp::GetRangeKeyInfo(bool aLowerBound, Key* aKey, bool* aOpen)
if (range.isOnly()) {
*aKey = range.lower();
*aOpen = false;
#ifdef ENABLE_INTL_API
if (mCursor->IsLocaleAware()) {
range.lower().ToLocaleBasedKey(*aKey, mCursor->mLocale);
}
#endif
} else {
*aKey = aLowerBound ? range.lower() : range.upper();
*aOpen = aLowerBound ? range.lowerOpen() : range.upperOpen();
#ifdef ENABLE_INTL_API
if (mCursor->IsLocaleAware()) {
if (aLowerBound) {
range.lower().ToLocaleBasedKey(*aKey, mCursor->mLocale);
@ -27982,7 +27969,6 @@ OpenOp::GetRangeKeyInfo(bool aLowerBound, Key* aKey, bool* aOpen)
range.upper().ToLocaleBasedKey(*aKey, mCursor->mLocale);
}
}
#endif
}
} else {
*aOpen = false;

Просмотреть файл

@ -65,13 +65,11 @@ IDBCursor::IDBCursor(Type aType,
}
}
#ifdef ENABLE_INTL_API
bool
IDBCursor::IsLocaleAware() const
{
return mSourceIndex && !mSourceIndex->Locale().IsEmpty();
}
#endif
IDBCursor::~IDBCursor()
{
@ -437,7 +435,6 @@ IDBCursor::Continue(JSContext* aCx,
return;
}
#ifdef ENABLE_INTL_API
if (IsLocaleAware() && !key.IsUnset()) {
Key tmp;
aRv = key.ToLocaleBasedKey(tmp, mSourceIndex->Locale());
@ -448,9 +445,6 @@ IDBCursor::Continue(JSContext* aCx,
}
const Key& sortKey = IsLocaleAware() ? mSortKey : mKey;
#else
const Key& sortKey = mKey;
#endif
if (!key.IsUnset()) {
switch (mDirection) {
@ -547,7 +541,6 @@ IDBCursor::ContinuePrimaryKey(JSContext* aCx,
return;
}
#ifdef ENABLE_INTL_API
if (IsLocaleAware() && !key.IsUnset()) {
Key tmp;
aRv = key.ToLocaleBasedKey(tmp, mSourceIndex->Locale());
@ -558,9 +551,6 @@ IDBCursor::ContinuePrimaryKey(JSContext* aCx,
}
const Key& sortKey = IsLocaleAware() ? mSortKey : mKey;
#else
const Key& sortKey = mKey;
#endif
if (key.IsUnset()) {
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_DATA_ERR);

Просмотреть файл

@ -205,11 +205,9 @@ private:
~IDBCursor();
#ifdef ENABLE_INTL_API
// Checks if this is a locale aware cursor (ie. the index's sortKey is unset)
bool
IsLocaleAware() const;
#endif
void
DropJSObjects();

Просмотреть файл

@ -1316,9 +1316,7 @@ IDBObjectStore::AppendIndexUpdateInfo(
{
nsresult rv;
#ifdef ENABLE_INTL_API
const bool localeAware = !aLocale.IsEmpty();
#endif
if (!aMultiEntry) {
Key key;
@ -1336,14 +1334,12 @@ IDBObjectStore::AppendIndexUpdateInfo(
IndexUpdateInfo* updateInfo = aUpdateInfoArray.AppendElement();
updateInfo->indexId() = aIndexID;
updateInfo->value() = key;
#ifdef ENABLE_INTL_API
if (localeAware) {
rv = key.ToLocaleBasedKey(updateInfo->localizedValue(), aLocale);
if (NS_WARN_IF(NS_FAILED(rv))) {
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
}
}
#endif
return NS_OK;
}
@ -1383,14 +1379,12 @@ IDBObjectStore::AppendIndexUpdateInfo(
IndexUpdateInfo* updateInfo = aUpdateInfoArray.AppendElement();
updateInfo->indexId() = aIndexID;
updateInfo->value() = value;
#ifdef ENABLE_INTL_API
if (localeAware) {
rv = value.ToLocaleBasedKey(updateInfo->localizedValue(), aLocale);
if (NS_WARN_IF(NS_FAILED(rv))) {
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
}
}
#endif
}
}
else {
@ -1404,14 +1398,12 @@ IDBObjectStore::AppendIndexUpdateInfo(
IndexUpdateInfo* updateInfo = aUpdateInfoArray.AppendElement();
updateInfo->indexId() = aIndexID;
updateInfo->value() = value;
#ifdef ENABLE_INTL_API
if (localeAware) {
rv = value.ToLocaleBasedKey(updateInfo->localizedValue(), aLocale);
if (NS_WARN_IF(NS_FAILED(rv))) {
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
}
}
#endif
}
return NS_OK;
@ -2277,11 +2269,9 @@ IDBObjectStore::CreateIndex(const nsAString& aName,
// Valid locale names are always ASCII as per BCP-47.
nsCString locale = NS_LossyConvertUTF16toASCII(aOptionalParameters.mLocale);
bool autoLocale = locale.EqualsASCII("auto");
#ifdef ENABLE_INTL_API
if (autoLocale) {
locale = IndexedDatabaseManager::GetLocale();
}
#endif
IndexMetadata* metadata = indexes.AppendElement(
IndexMetadata(transaction->NextIndexId(), nsString(aName), keyPath,

Просмотреть файл

@ -45,6 +45,8 @@
#include "ScriptErrorHelper.h"
#include "WorkerScope.h"
#include "WorkerPrivate.h"
#include "nsCharSeparatedTokenizer.h"
#include "unicode/locid.h"
// Bindings for ResolveConstructors
#include "mozilla/dom/IDBCursorBinding.h"
@ -59,11 +61,6 @@
#include "mozilla/dom/IDBTransactionBinding.h"
#include "mozilla/dom/IDBVersionChangeEventBinding.h"
#ifdef ENABLE_INTL_API
#include "nsCharSeparatedTokenizer.h"
#include "unicode/locid.h"
#endif
#define IDB_STR "indexedDB"
// The two possible values for the data argument when receiving the disk space
@ -430,7 +427,6 @@ IndexedDatabaseManager::Init()
Preferences::RegisterCallbackAndCall(MaxSerializedMsgSizePrefChangeCallback,
kPrefMaxSerilizedMsgSize);
#ifdef ENABLE_INTL_API
nsAutoCString acceptLang;
Preferences::GetLocalizedCString("intl.accept_languages", acceptLang);
@ -449,7 +445,6 @@ IndexedDatabaseManager::Init()
if (mLocale.IsEmpty()) {
mLocale.AssignLiteral("en_US");
}
#endif
return NS_OK;
}
@ -1093,7 +1088,6 @@ IndexedDatabaseManager::LoggingModePrefChangedCallback(
}
}
#ifdef ENABLE_INTL_API
// static
const nsCString&
IndexedDatabaseManager::GetLocale()
@ -1103,7 +1097,6 @@ IndexedDatabaseManager::GetLocale()
return idbManager->mLocale;
}
#endif
NS_IMPL_ADDREF(IndexedDatabaseManager)
NS_IMPL_RELEASE_WITH_DESTROY(IndexedDatabaseManager, Destroy())

Просмотреть файл

@ -189,10 +189,8 @@ public:
nsresult
FlushPendingFileDeletions();
#ifdef ENABLE_INTL_API
static const nsCString&
GetLocale();
#endif
static mozilla::Mutex&
FileMutex()
@ -241,9 +239,7 @@ private:
// and FileInfo.mSliceRefCnt
mozilla::Mutex mFileMutex;
#ifdef ENABLE_INTL_API
nsCString mLocale;
#endif
indexedDB::BackgroundUtilsChild* mBackgroundActor;

Просмотреть файл

@ -22,11 +22,8 @@
#include "nsAlgorithm.h"
#include "nsJSUtils.h"
#include "ReportInternalError.h"
#include "xpcpublic.h"
#ifdef ENABLE_INTL_API
#include "unicode/ucol.h"
#endif
#include "xpcpublic.h"
namespace mozilla {
namespace dom {
@ -110,7 +107,7 @@ namespace indexedDB {
[1, 2] // 0x60 bf f0 0 0 0 0 0 0 0x10 c0
[[]] // 0x80
*/
#ifdef ENABLE_INTL_API
nsresult
Key::ToLocaleBasedKey(Key& aTarget, const nsCString& aLocale) const
{
@ -207,7 +204,6 @@ Key::ToLocaleBasedKey(Key& aTarget, const nsCString& aLocale) const
aTarget.TrimBuffer();
return NS_OK;
}
#endif
nsresult
Key::EncodeJSValInternal(JSContext* aCx, JS::Handle<JS::Value> aVal,
@ -507,7 +503,6 @@ Key::EncodeAsString(const T* aStart, const T* aEnd, uint8_t aType)
return NS_OK;
}
#ifdef ENABLE_INTL_API
nsresult
Key::EncodeLocaleString(const nsDependentString& aString, uint8_t aTypeOffset,
const nsCString& aLocale)
@ -545,7 +540,6 @@ Key::EncodeLocaleString(const nsDependentString& aString, uint8_t aTypeOffset,
keyBuffer.Elements()+sortKeyLength,
aTypeOffset);
}
#endif
// static
nsresult

Просмотреть файл

@ -214,10 +214,8 @@ public:
nsresult
AppendItem(JSContext* aCx, bool aFirstOfArray, JS::Handle<JS::Value> aVal);
#ifdef ENABLE_INTL_API
nsresult
ToLocaleBasedKey(Key& aTarget, const nsCString& aLocale) const;
#endif
void
FinishArray()
@ -298,11 +296,9 @@ private:
nsresult
EncodeAsString(const T* aStart, const T* aEnd, uint8_t aType);
#ifdef ENABLE_INTL_API
nsresult
EncodeLocaleString(const nsDependentString& aString, uint8_t aTypeOffset,
const nsCString& aLocale);
#endif
void
EncodeNumber(double aFloat, uint8_t aType);

Просмотреть файл

@ -7,7 +7,10 @@
with Files("**"):
BUG_COMPONENT = ("Core", "DOM: IndexedDB")
MOCHITEST_MANIFESTS += ['test/mochitest.ini']
MOCHITEST_MANIFESTS += [
'test/mochitest-intl-api.ini',
'test/mochitest.ini',
]
BROWSER_CHROME_MANIFESTS += ['test/browser.ini']
@ -18,9 +21,6 @@ XPCSHELL_TESTS_MANIFESTS += [
'test/unit/xpcshell-parent-process.ini'
]
if CONFIG['ENABLE_INTL_API']:
MOCHITEST_MANIFESTS += ['test/mochitest-intl-api.ini']
EXPORTS.mozilla.dom += [
'IDBCursor.h',
'IDBDatabase.h',

Просмотреть файл

@ -106,9 +106,9 @@ enum class CubebState {
Shutdown
} sCubebState = CubebState::Uninitialized;
cubeb* sCubebContext;
double sVolumeScale;
uint32_t sCubebPlaybackLatencyInMilliseconds;
uint32_t sCubebMSGLatencyInFrames;
double sVolumeScale = 1.0;
uint32_t sCubebPlaybackLatencyInMilliseconds = 100;
uint32_t sCubebMSGLatencyInFrames = 512;
bool sCubebPlaybackLatencyPrefSet;
bool sCubebMSGLatencyPrefSet;
bool sAudioStreamInitEverSucceeded = false;

Просмотреть файл

@ -3,6 +3,7 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
include('/media/webrtc/webrtc.mozbuild')
FILES_PER_UNIFIED_FILE = 6
@ -316,11 +317,6 @@ if CONFIG['MOZ_WEBRTC']:
DEFINES['MOZILLA_INTERNAL_API'] = True
if CONFIG['OS_TARGET'] == 'WINNT':
DEFINES['WEBRTC_WIN'] = True
else:
DEFINES['WEBRTC_POSIX'] = True
if CONFIG['ANDROID_VERSION'] > '15':
DEFINES['MOZ_OMX_WEBM_DECODER'] = True

Просмотреть файл

@ -3,6 +3,7 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
include('/media/webrtc/webrtc.mozbuild')
if CONFIG['MOZ_WEBRTC']:
EXPORTS += [
@ -22,12 +23,6 @@ if CONFIG['MOZ_WEBRTC']:
'/media/webrtc/signaling',
'/media/webrtc/trunk',
]
if CONFIG['OS_TARGET'] == 'WINNT':
DEFINES['WEBRTC_WIN'] = True
else:
DEFINES['WEBRTC_POSIX'] = True
# Must match build/gyp.mozbuild: enable_libevent
DEFINES['WEBRTC_BUILD_LIBEVENT'] = True
if CONFIG['OS_TARGET'] == 'Android':
DEFINES['WEBRTC_ANDROID'] = True

Просмотреть файл

@ -3,6 +3,7 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
include('/media/webrtc/webrtc.mozbuild')
with Files('*'):
BUG_COMPONENT = ('Core', 'WebRTC: Audio/Video')
@ -20,10 +21,6 @@ EXPORTS += [
]
if CONFIG['MOZ_WEBRTC']:
if CONFIG['OS_TARGET'] == 'WINNT':
DEFINES['WEBRTC_WIN'] = True
else:
DEFINES['WEBRTC_POSIX'] = True
EXPORTS += ['AudioOutputObserver.h',
'MediaEngineRemoteVideoSource.h',
'MediaEngineWebRTC.h']

Просмотреть файл

@ -4,11 +4,13 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "BasicCardPayment.h"
#include "mozilla/dom/Element.h"
#include "mozilla/dom/PaymentRequest.h"
#include "mozilla/dom/PaymentResponse.h"
#include "nsContentUtils.h"
#include "BasicCardPayment.h"
#include "nsIURLParser.h"
#include "nsNetCID.h"
#include "PaymentRequestManager.h"
namespace mozilla {
@ -52,6 +54,191 @@ PaymentRequest::PrefEnabled(JSContext* aCx, JSObject* aObj)
return Preferences::GetBool("dom.payments.request.enabled");
}
nsresult
PaymentRequest::IsValidStandardizedPMI(const nsAString& aIdentifier,
nsAString& aErrorMsg)
{
/*
* The syntax of a standardized payment method identifier is given by the
* following [ABNF]:
*
* stdpmi = part *( "-" part )
* part = 1loweralpha *( DIGIT / loweralpha )
* loweralpha = %x61-7A
*/
nsString::const_iterator start, end;
aIdentifier.BeginReading(start);
aIdentifier.EndReading(end);
while (start != end) {
// the first char must be in the range %x61-7A
if ((*start < 'a' || *start > 'z')) {
aErrorMsg.AssignLiteral("'");
aErrorMsg.Append(aIdentifier);
aErrorMsg.AppendLiteral("' is not valid. The character '");
aErrorMsg.Append(*start);
aErrorMsg.AppendLiteral("' at the beginning or after the '-' must be in the range [a-z].");
return NS_ERROR_RANGE_ERR;
}
++start;
// the rest can be in the range %x61-7A + DIGITs
while (start != end && *start != '-' &&
((*start >= 'a' && *start <= 'z') || (*start >= '0' && *start <= '9'))) {
++start;
}
// if the char is not in the range %x61-7A + DIGITs, it must be '-'
if (start != end && *start != '-') {
aErrorMsg.AssignLiteral("'");
aErrorMsg.Append(aIdentifier);
aErrorMsg.AppendLiteral("' is not valid. The character '");
aErrorMsg.Append(*start);
aErrorMsg.AppendLiteral("' must be in the range [a-zA-z0-9-].");
return NS_ERROR_RANGE_ERR;
}
if (*start == '-') {
++start;
// the last char can not be '-'
if (start == end) {
aErrorMsg.AssignLiteral("'");
aErrorMsg.Append(aIdentifier);
aErrorMsg.AppendLiteral("' is not valid. The last character '");
aErrorMsg.Append(*start);
aErrorMsg.AppendLiteral("' must be in the range [a-z0-9].");
return NS_ERROR_RANGE_ERR;
}
}
}
return NS_OK;
}
nsresult
PaymentRequest::IsValidPaymentMethodIdentifier(const nsAString& aIdentifier,
nsAString& aErrorMsg)
{
if (aIdentifier.IsEmpty()) {
aErrorMsg.AssignLiteral("Payment method identifier is required.");
return NS_ERROR_TYPE_ERR;
}
/*
* URL-based payment method identifier
*
* 1. If url's scheme is not "https", return false.
* 2. If url's username or password is not the empty string, return false.
* 3. Otherwise, return true.
*/
nsCOMPtr<nsIURLParser> urlParser = do_GetService(NS_STDURLPARSER_CONTRACTID);
MOZ_ASSERT(urlParser);
uint32_t schemePos = 0;
int32_t schemeLen = 0;
uint32_t authorityPos = 0;
int32_t authorityLen = 0;
NS_ConvertUTF16toUTF8 url(aIdentifier);
nsresult rv = urlParser->ParseURL(url.get(),
url.Length(),
&schemePos, &schemeLen,
&authorityPos, &authorityLen,
nullptr, nullptr);
NS_ENSURE_SUCCESS(rv, NS_ERROR_RANGE_ERR);
if (schemeLen == -1) {
// The PMI is not a URL-based PMI, check if it is a standardized PMI
return IsValidStandardizedPMI(aIdentifier, aErrorMsg);
}
if (!Substring(aIdentifier, schemePos, schemeLen).EqualsASCII("https")) {
aErrorMsg.AssignLiteral("'");
aErrorMsg.Append(aIdentifier);
aErrorMsg.AppendLiteral("' is not valid. The scheme must be 'https'.");
return NS_ERROR_RANGE_ERR;
}
if (Substring(aIdentifier, authorityPos, authorityLen).IsEmpty()) {
aErrorMsg.AssignLiteral("'");
aErrorMsg.Append(aIdentifier);
aErrorMsg.AppendLiteral("' is not valid. hostname can not be empty.");
return NS_ERROR_RANGE_ERR;
}
uint32_t usernamePos = 0;
int32_t usernameLen = 0;
uint32_t passwordPos = 0;
int32_t passwordLen = 0;
uint32_t hostnamePos = 0;
int32_t hostnameLen = 0;
int32_t port = 0;
NS_ConvertUTF16toUTF8 authority(Substring(aIdentifier, authorityPos, authorityLen));
rv = urlParser->ParseAuthority(authority.get(),
authority.Length(),
&usernamePos, &usernameLen,
&passwordPos, &passwordLen,
&hostnamePos, &hostnameLen,
&port);
if (NS_FAILED(rv)) {
// Handle the special cases that URLParser treats it as an invalid URL, but
// are used in web-platform-test
// For exmaple:
// https://:@example.com // should be considered as valid
// https://:password@example.com. // should be considered as invalid
int32_t atPos = authority.FindChar('@');
if (atPos >= 0) {
// only accept the case https://:@xxx
if (atPos == 1 && authority.CharAt(0) == ':') {
usernamePos = 0;
usernameLen = 0;
passwordPos = 0;
passwordLen = 0;
} else {
// for the fail cases, don't care about what the actual length is.
usernamePos = 0;
usernameLen = INT32_MAX;
passwordPos = 0;
passwordLen = INT32_MAX;
}
} else {
usernamePos = 0;
usernameLen = -1;
passwordPos = 0;
passwordLen = -1;
}
// Parse server information when both username and password are empty or do not
// exist.
if ((usernameLen <= 0) && (passwordLen <= 0)) {
if (authority.Length() - atPos - 1 == 0) {
aErrorMsg.AssignLiteral("'");
aErrorMsg.Append(aIdentifier);
aErrorMsg.AppendLiteral("' is not valid. hostname can not be empty.");
return NS_ERROR_RANGE_ERR;
}
// Re-using nsIURLParser::ParseServerInfo to extract the hostname and port
// information. This can help us to handle complicated IPv6 cases.
nsAutoCString serverInfo(Substring(authority,
atPos + 1,
authority.Length() - atPos - 1));
rv = urlParser->ParseServerInfo(serverInfo.get(),
serverInfo.Length(),
&hostnamePos, &hostnameLen, &port);
if (NS_FAILED(rv)) {
// ParseServerInfo returns NS_ERROR_MALFORMED_URI in all fail cases, we
// probably need a followup bug to figure out the fail reason.
return NS_ERROR_RANGE_ERR;
}
}
}
// PMI is valid when usernameLen/passwordLen equals to -1 or 0.
if (usernameLen > 0 || passwordLen > 0) {
aErrorMsg.AssignLiteral("'");
aErrorMsg.Append(aIdentifier);
aErrorMsg.AssignLiteral("' is not valid. Username and password must be empty.");
return NS_ERROR_RANGE_ERR;
}
// PMI is valid when hostnameLen is larger than 0
if (hostnameLen <= 0) {
aErrorMsg.AssignLiteral("'");
aErrorMsg.Append(aIdentifier);
aErrorMsg.AppendLiteral("' is not valid. hostname can not be empty.");
return NS_ERROR_RANGE_ERR;
}
return NS_OK;
}
nsresult
PaymentRequest::IsValidMethodData(JSContext* aCx,
const Sequence<PaymentMethodData>& aMethodData,
@ -63,11 +250,12 @@ PaymentRequest::IsValidMethodData(JSContext* aCx,
}
for (const PaymentMethodData& methodData : aMethodData) {
if (methodData.mSupportedMethods.IsEmpty()) {
aErrorMsg.AssignLiteral(
"Payment method identifier is required.");
return NS_ERROR_TYPE_ERR;
nsresult rv = IsValidPaymentMethodIdentifier(methodData.mSupportedMethods,
aErrorMsg);
if (NS_FAILED(rv)) {
return rv;
}
RefPtr<BasicCardService> service = BasicCardService::GetService();
MOZ_ASSERT(service);
if (service->IsBasicCardPayment(methodData.mSupportedMethods)) {
@ -299,6 +487,10 @@ PaymentRequest::IsValidDetailsBase(const PaymentDetailsBase& aDetails, nsAString
if (aDetails.mModifiers.WasPassed()) {
const Sequence<PaymentDetailsModifier>& modifiers = aDetails.mModifiers.Value();
for (const PaymentDetailsModifier& modifier : modifiers) {
rv = IsValidPaymentMethodIdentifier(modifier.mSupportedMethods, aErrorMsg);
if (NS_FAILED(rv)) {
return rv;
}
rv = IsValidCurrencyAmount(NS_LITERAL_STRING("details.modifiers.total"),
modifier.mTotal.mAmount,
true, // isTotalItem
@ -377,7 +569,11 @@ PaymentRequest::Constructor(const GlobalObject& aGlobal,
aMethodData,
message);
if (NS_FAILED(rv)) {
aRv.ThrowTypeError<MSG_ILLEGAL_TYPE_PR_CONSTRUCTOR>(message);
if (rv == NS_ERROR_TYPE_ERR) {
aRv.ThrowTypeError<MSG_ILLEGAL_TYPE_PR_CONSTRUCTOR>(message);
} else if (rv == NS_ERROR_RANGE_ERR) {
aRv.ThrowRangeError<MSG_ILLEGAL_RANGE_PR_CONSTRUCTOR>(message);
}
return nullptr;
}
rv = IsValidDetailsInit(aDetails, message);

Просмотреть файл

@ -36,6 +36,12 @@ public:
static bool PrefEnabled(JSContext* aCx, JSObject* aObj);
static nsresult IsValidStandardizedPMI(const nsAString& aIdentifier,
nsAString& aErrorMsg);
static nsresult IsValidPaymentMethodIdentifier(const nsAString& aIdentifier,
nsAString& aErrorMsg);
static nsresult IsValidMethodData(JSContext* aCx,
const Sequence<PaymentMethodData>& aMethodData,
nsAString& aErrorMsg);

Просмотреть файл

@ -0,0 +1,58 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
const { XPCOMUtils } = Cu.import("resource://gre/modules/XPCOMUtils.jsm");
const paymentSrv = Cc["@mozilla.org/dom/payments/payment-request-service;1"].getService(Ci.nsIPaymentRequestService);
const UIService = {
showPayment: function(requestId) {
paymentSrv.changeShippingOption(requestId, "");
},
abortPayment: function(requestId) {
let abortResponse = Cc["@mozilla.org/dom/payments/payment-abort-action-response;1"].
createInstance(Ci.nsIPaymentAbortActionResponse);
abortResponse.init(requestId, Ci.nsIPaymentActionResponse.ABORT_SUCCEEDED);
paymentSrv.respondPayment(abortResponse.QueryInterface(Ci.nsIPaymentActionResponse));
},
completePayment: function(requestId) {
const completeResponse = Cc["@mozilla.org/dom/payments/payment-complete-action-response;1"].
createInstance(Ci.nsIPaymentCompleteActionResponse);
completeResponse.init(requestId, Ci.nsIPaymentActionResponse.COMPLETE_SUCCEEDED);
paymentSrv.respondPayment(completeResponse.QueryInterface(Ci.nsIPaymentActionResponse));
},
updatePayment: function(requestId) {
const showResponseData = Cc["@mozilla.org/dom/payments/general-response-data;1"].
createInstance(Ci.nsIGeneralResponseData);
showResponseData.initData({ paymentToken: "6880281f-0df3-4b8e-916f-66575e2457c1",});
const showResponse = Cc["@mozilla.org/dom/payments/payment-show-action-response;1"].
createInstance(Ci.nsIPaymentShowActionResponse);
showResponse.init(requestId,
Ci.nsIPaymentActionResponse.PAYMENT_ACCEPTED,
"https://example.com", // payment method
showResponseData, // payment method data
"Bill A. Pacheco", // payer name
"", // payer email
""); // payer phone
paymentSrv.respondPayment(showResponse.QueryInterface(Ci.nsIPaymentActionResponse));
},
QueryInterface: XPCOMUtils.generateQI([Ci.nsIPaymentUIService]),
};
function emitTestFail(message) {
sendAsyncMessage("test-fail", message);
}
addMessageListener("set-ui-service", function() {
paymentSrv.setTestingUIService(UIService.QueryInterface(Ci.nsIPaymentUIService));
});
addMessageListener("teardown", function() {
paymentSrv.cleanup();
sendAsyncMessage("teardown-complete");
});

Просмотреть файл

@ -7,7 +7,7 @@ function checkSimplePayment(aSimplePayment) {
const methodData = aSimplePayment.paymentMethods.queryElementAt(0, Ci.nsIPaymentMethodData);
ok(methodData, "Fail to get payment methodData.");
is(methodData.supportedMethods, "MyPay", "supported method should be 'MyPay'.");
is(methodData.supportedMethods, "basic-card", "supported method should be 'basic-card'.");
ok(!methodData.data, "methodData.data should not exist.");
// checking the passed PaymentDetails parameter
@ -36,7 +36,7 @@ function checkDupShippingOptionsPayment(aPayment) {
const methodData = aPayment.paymentMethods.queryElementAt(0, Ci.nsIPaymentMethodData);
ok(methodData, "Fail to get payment methodData.");
is(methodData.supportedMethods, "MyPay", "methodData.supportedMethod name should be 'MyPay'.");
is(methodData.supportedMethods, "basic-card", "methodData.supportedMethod name should be 'basic-card'.");
ok(!methodData.data, "methodData.data should not exist.");
// checking the passed PaymentDetails parameter

Просмотреть файл

@ -8,6 +8,7 @@ support-files =
ConstructorChromeScript.js
CurrencyAmountValidationChromeScript.js
GeneralChromeScript.js
PMIValidationChromeScript.js
ShowPaymentChromeScript.js
[test_abortPayment.html]
@ -18,4 +19,5 @@ run-if = nightly_build # Bug 1390737: Depends on the Nightly-only UI service
[test_constructor.html]
[test_currency_amount_validation.html]
[test_payment-request-in-iframe.html]
[test_pmi_validation.html]
[test_showPayment.html]

Просмотреть файл

@ -9,7 +9,7 @@
<script type="text/javascript">
const supportedInstruments = [{
supportedMethods: "MyPay",
supportedMethods: "basic-card",
}];
const details = {
id: "simple details",

Просмотреть файл

@ -88,11 +88,6 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1345367
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1345367">Mozilla Bug 1345367</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
</pre>
</body>
</html>

Просмотреть файл

@ -288,11 +288,5 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1375345
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1375345">Mozilla Bug 1375345</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
</pre>
</body>
</html>

Просмотреть файл

@ -159,11 +159,5 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1345365
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1345365">Mozilla Bug 1345365</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
</pre>
</body>
</html>

Просмотреть файл

@ -376,11 +376,5 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1388661
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1367669">Mozilla Bug 1367669</a>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1388661">Mozilla Bug 1388661</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
</pre>
</body>
</html>

Просмотреть файл

@ -93,10 +93,5 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1318988
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1318988">Mozilla Bug 1318988</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
</pre>
</body>
</html>

Просмотреть файл

@ -0,0 +1,241 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=1389418
-->
<head>
<meta charset="utf-8">
<title>Test for PaymentRequest API payment method identifier validation</title>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript">
"use strict";
SimpleTest.waitForExplicitFinish();
var gUrl = SimpleTest.getTestFileURL('PMIValidationChromeScript.js');
var gScript = SpecialPowers.loadChromeScript(gUrl);
function testFailHandler(message) {
ok(false, message);
}
gScript.addMessageListener("test-fail", testFailHandler);
const defaultMethods = [{
supportedMethods: "basic-card",
}];
const defaultDetails = {
total: {
label: "total",
amount: {
currency: "usd",
value: "1.00",
},
},
};
const validPMIs = [
"https://wpt",
"https://wpt.fyi/",
"https://wpt.fyi/payment",
"https://wpt.fyi/payment-request",
"https://wpt.fyi/payment-request?",
"https://wpt.fyi/payment-request?this=is",
"https://wpt.fyi/payment-request?this=is&totally",
"https://wpt.fyi:443/payment-request?this=is&totally",
"https://wpt.fyi:443/payment-request?this=is&totally#fine",
"https://:@wpt.fyi:443/payment-request?this=is&totally#👍",
" \thttps://wpt\n ",
"https://xn--c1yn36f",
"https://點看",
"e",
"n6jzof05mk2g4lhxr-u-q-w1-c-i-pa-ty-bdvs9-ho-ae7-p-md8-s-wq3-h-qd-e-q-sa",
"a-b-q-n-s-pw0",
"m-u",
"s-l5",
"k9-f",
"m-l",
"u4-n-t",
"i488jh6-g18-fck-yb-v7-i",
"x-x-t-t-c34-o",
"basic-card",
];
const invalidPMIs = [
"https://:password@example.com",
"https://username@example.com",
"https://username:password@example.com/pay",
"http://username:password@example.com/pay",
"https://:@example.com:100000000/pay",
"https://foo.com:100000000/pay",
"basic-💳",
"not-https://wpt.fyi/payment-request",
"../realitive/url",
"/absolute/../path?",
"https://",
"¡basic-*-card!",
"Basic-Card",
"0",
"-",
"--",
"a--b",
"-a--b",
"a-b-",
"0-",
"0-a",
"a0--",
"A-",
"A-B",
"A-b",
"a-0",
"a-0b",
" a-b",
"\t\na-b",
"a-b ",
"a-b\n\t",
];
function testWithValidPMIs() {
return new Promise((resolve, reject) => {
for (const validPMI of validPMIs) {
try {
const validMethods = [{supportedMethods: validPMI},];
const payRequest = new PaymentRequest(validMethods, defaultDetails);
resolve();
} catch (e) {
ok(false, "Unexpected error '" + e.name + "'.");
resolve();
}
}
});
}
function testWithInvalidPMIs() {
return new Promise((resolve, reject) => {
for (const invalidPMI of invalidPMIs) {
try {
const invalidMethods = [{supportedMethods: invalidPMI},];
const payRequest = new PaymentRequest(invalidMethods, defaultDetails);
ok(false, "Expected throw 'RangeError', but got resolved");
resolve();
} catch (e) {
is(e.name, "RangeError", "Expected 'RangeError'.");
resolve();
}
}
});
}
function testUpdateWithValidPMI() {
gScript.sendAsyncMessage("set-ui-service");
return new Promise((resolve, reject) => {
const payRequest = new PaymentRequest(defaultMethods, defaultDetails);
payRequest.addEventListener("shippingoptionchange", event => {
const validDetails = {
total: {
label: "total",
amount: {
currency: "USD",
value: "1.00",
},
},
modifiers: [{
supportedMethods: "https://example.com",
total: {
label: "total",
amount: {
currency: "USD",
value: "1.00",
},
}
},],
}
event.updateWith(validDetails);
});
payRequest.show().then((response) => {
response.complete("success").then(() => {
resolve();
}).catch((e) => {
ok(false, "Unexpected error '" + e.name + "'.");
resolve();
});
}).catch((e) => {
ok(false, "Unexpected error '" + e.name + "'.");
resolve();
});
});
}
function testUpdateWithInvalidPMI() {
gScript.sendAsyncMessage("set-ui-service");
return new Promise((resolve, reject) => {
const payRequest = new PaymentRequest(defaultMethods, defaultDetails);
payRequest.addEventListener("shippingoptionchange", event => {
const invalidDetails = {
total: {
label: "total",
amount: {
currency: "USD",
value: "1.00",
},
},
modifiers: [{
supportedMethods: "https://username:password@example.com",
total: {
label: "total",
amount: {
currency: "USD",
value: "1.00",
},
},
},],
}
event.updateWith(invalidDetails);
});
payRequest.show().then((result) => {
ok(false, "Expected throw 'RangeError', but got resolved.");
resolve();
}).catch((e) => {
is(e.name, "RangeError", "Expected 'RangeError'.");
resolve();
});
});
}
function teardown() {
gScript.addMessageListener("teardown-complete", function teardownCompleteHandler() {
gScript.removeMessageListener("teardown-complete", teardownCompleteHandler);
gScript.removeMessageListener("test-fail", testFailHandler)
gScript.destroy();
SimpleTest.finish();
});
gScript.sendAsyncMessage("teardown");
}
function runTests() {
testWithValidPMIs()
.then(testWithInvalidPMIs)
.then(testUpdateWithValidPMI)
.then(testUpdateWithInvalidPMI)
.then(teardown)
.catch( e => {
ok(false, "Unexpected error: " + e.name);
SimpleTest.finish();
});
}
window.addEventListener('load', function() {
SpecialPowers.pushPrefEnv({
'set': [
['dom.payments.request.enabled', true],
]
}, runTests);
});
</script>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1389418">Mozilla Bug 1389418</a>
</body>
</html>

Просмотреть файл

@ -300,11 +300,5 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1345366
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1345366">Mozilla Bug 1345366</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
</pre>
</body>
</html>

Просмотреть файл

@ -513,8 +513,6 @@ var interfaceNamesInGlobalScope =
"HTMLScriptElement",
// IMPORTANT: Do not change this list without review from a DOM peer!
"HTMLSelectElement",
// IMPORTANT: Do not change this list without review from a DOM peer!
{name: "HTMLShadowElement", stylo: false},
// IMPORTANT: Do not change this list without review from a DOM peer!
"HTMLSourceElement",
// IMPORTANT: Do not change this list without review from a DOM peer!

Просмотреть файл

@ -33,8 +33,6 @@ support-files =
skip-if = stylo # bug 1293844
[test_dest_insertion_points.html]
skip-if = stylo # bug 1293844
[test_dest_insertion_points_shadow.html]
skip-if = stylo # bug 1293844
[test_fallback_dest_insertion_points.html]
skip-if = stylo # bug 1293844
[test_detached_style.html]
@ -53,8 +51,6 @@ skip-if = true # disabled - See bug 1390396
[test_document_register_stack.html]
skip-if = true # disabled - See bug 1390396
[test_document_shared_registry.html]
[test_event_dispatch.html]
skip-if = stylo # bug 1293844
[test_event_retarget.html]
skip-if = stylo # bug 1293844
[test_event_stopping.html]
@ -66,16 +62,10 @@ skip-if = stylo # bug 1293844
skip-if = stylo # bug 1293844
[test_shadowroot_inert_element.html]
skip-if = stylo # bug 1293844
[test_shadowroot_host.html]
skip-if = stylo # bug 1293844
[test_shadowroot_style.html]
skip-if = stylo # bug 1293844
[test_shadowroot_style_multiple_shadow.html]
skip-if = stylo # bug 1293844
[test_shadowroot_style_order.html]
skip-if = stylo # bug 1293844
[test_shadowroot_youngershadowroot.html]
skip-if = stylo # bug 1293844
[test_style_fallback_content.html]
skip-if = stylo # bug 1293844
[test_unresolved_pseudo_class.html]

Просмотреть файл

@ -1,68 +0,0 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=999999
-->
<head>
<meta charset="utf-8">
<title>Test for Bug 999999</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=999999">Mozilla Bug 999999</a>
<p id="display"></p>
<div id="content">
<div id="shadowhost"></div>
</div>
<pre id="test">
</pre>
<script type="application/javascript">
/** Test for Bug 999999 **/
var host = document.getElementById("shadowhost");
// Test destination insertion points of node distributed to shadow element.
var olderShadowRoot = host.createShadowRoot();
var youngerShadowRoot = host.createShadowRoot();
var shadowElem = document.createElement("shadow");
youngerShadowRoot.appendChild(shadowElem);
var span = document.createElement("span");
olderShadowRoot.appendChild(span);
is(span.getDestinationInsertionPoints().length, 1, "Child of ShadowRoot should be distributed to shadow insertion point.");
is(span.getDestinationInsertionPoints()[0], shadowElem, "Shadow element should be in destination insertion point list.");
// Test destination insertion points of node removed from tree.
olderShadowRoot.removeChild(span);
is(span.getDestinationInsertionPoints().length, 0, "Node removed from tree should no longer be distributed.");
// Test destination insertion points of fallback content being reprojected into a shadow element.
var content = document.createElement("content");
var fallback = document.createElement("span");
content.appendChild(fallback);
olderShadowRoot.appendChild(content);
is(fallback.getDestinationInsertionPoints().length, 2, "The fallback content should have 2 destination insertion points, the parent content and the shadow element to which it is reprojected.");
is(fallback.getDestinationInsertionPoints()[0], content, "First destination of the fallback content should be the parent content element.");
is(fallback.getDestinationInsertionPoints()[1], shadowElem, "Second destination of the fallback content should be the shadow element to which the element is reprojected.");
// Test destination insertion points of fallback content being removed from tree.
content.removeChild(fallback);
is(fallback.getDestinationInsertionPoints().length, 0, "The content should no longer be distributed to any nodes because it is no longer fallback content.");
// Test destination insertion points of distributed content after removing shadow insertion point.
var div = document.createElement("div");
olderShadowRoot.appendChild(div);
is(div.getDestinationInsertionPoints().length, 1, "Children in older shadow root should be distributed to shadow insertion point.");
is(div.getDestinationInsertionPoints()[0], shadowElem, "Destination insertion point should include shadow element.");
youngerShadowRoot.removeChild(shadowElem);
is(div.getDestinationInsertionPoints().length, 0, "Destination insertion points should be empty after removing shadow element.");
</script>
</body>
</html>

Просмотреть файл

@ -107,7 +107,6 @@ function startTest() {
var constructedButton = new buttonConstructor();
is(constructedButton.tagName, "BUTTON", "Created element should have local name of BUTTON");
is(constructedButton.__proto__, extendedProto, "Created element should have the prototype of the extended type.");
is(constructedButton.getAttribute("is"), "x-extended-button", "The |is| attribute of the created element should be the extended type.");
// Try creating an element with a custom element name, but not in the html namespace.
var htmlNamespaceProto = Object.create(HTMLElement.prototype);

Просмотреть файл

@ -291,11 +291,14 @@ function testAttributeChanged() {
function testAttributeChangedExtended() {
var p = Object.create(HTMLButtonElement.prototype);
var callbackCalled = false;
var callbackCalled = 0;
p.attributeChangedCallback = function(name, oldValue, newValue) {
is(callbackCalled, false, "Callback should only be called once in this test.");
callbackCalled = true;
runNextTest();
callbackCalled++;
if (callbackCalled > 2) {
is(false, "Got unexpected attribute changed callback.");
} else if (callbackCalled === 2) {
runNextTest();
}
};
document.registerElement("x-extended-attribute-change", { prototype: p, extends: "button" });

Просмотреть файл

@ -1,458 +0,0 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=887541
-->
<head>
<title>Test for event model in web components</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=887541">Bug 887541</a>
<script>
var els = SpecialPowers.Cc["@mozilla.org/eventlistenerservice;1"]
.getService(SpecialPowers.Ci.nsIEventListenerService);
function eventListener(e) {
eventChain.push(this);
}
function isEventChain(actual, expected, msg) {
is(actual.length, expected.length, msg);
for (var i = 0; i < expected.length; i++) {
is(actual[i], expected[i], msg + " at " + i);
}
// Check to make sure the event chain matches what we get back from nsIEventListenerService.getEventTargetChainFor
if (0 < actual.length) {
var chain = els.getEventTargetChainFor(actual[0], true); // Events should be dispatched on actual[0].
for (var i = 0; i < expected.length; i++) {
ok(SpecialPowers.compare(chain[i], expected[i]), msg + " at " + i + " for nsIEventListenerService");
}
}
}
/*
* Test 1: Test of event dispatch through a basic ShadowRoot with content a insertion point.
*
* <div elemOne> ------ <shadow-root shadowOne>
* | |
* <div elemTwo> <span elemThree>
* |
* <content elemFour>
*/
var elemOne = document.createElement("div");
elemOne.addEventListener("custom", eventListener);
var elemTwo = document.createElement("div");
elemTwo.addEventListener("custom", eventListener);
var elemThree = document.createElement("span");
elemThree.addEventListener("custom", eventListener);
var elemFour = document.createElement("content");
elemFour.addEventListener("custom", eventListener);
var shadowOne = elemOne.createShadowRoot();
shadowOne.addEventListener("custom", eventListener);
elemThree.appendChild(elemFour);
shadowOne.appendChild(elemThree);
elemOne.appendChild(elemTwo);
var eventChain = [];
var customEvent = new CustomEvent("custom", { "bubbles" : true, "composed" : true });
elemTwo.dispatchEvent(customEvent);
isEventChain(eventChain, [elemTwo, elemFour, elemThree, shadowOne, elemOne], "Event path for test 1 for event dispatched on elemTwo.");
/*
* Test 2: Test of event dispatch through a nested ShadowRoots with content insertion points.
*
* <div elemFive> --- <shadow-root shadowTwo>
* | |
* <div elemOne> <div elemFour> ----- <shadow-root shadowOne>
* | |
* <content elemTwo> <p elemSix>
* |
* <content elemThree>
*/
elemOne = document.createElement("div");
elemOne.addEventListener("custom", eventListener);
elemTwo = document.createElement("content");
elemTwo.addEventListener("custom", eventListener);
elemThree = document.createElement("content");
elemThree.addEventListener("custom", eventListener);
var elemFour = document.createElement("div");
elemFour.addEventListener("custom", eventListener);
var elemFive = document.createElement("div");
elemFive.addEventListener("custom", eventListener);
var elemSix = document.createElement("p");
elemSix.addEventListener("custom", eventListener);
var shadowOne = elemFour.createShadowRoot();
shadowOne.addEventListener("custom", eventListener);
var shadowTwo = elemFive.createShadowRoot();
shadowTwo.addEventListener("custom", eventListener);
elemFive.appendChild(elemOne);
shadowTwo.appendChild(elemFour);
elemFour.appendChild(elemTwo);
shadowOne.appendChild(elemSix);
elemSix.appendChild(elemThree);
eventChain = [];
customEvent = new CustomEvent("custom", { "bubbles" : true, "composed" : true });
elemOne.dispatchEvent(customEvent);
is(elemOne.getDestinationInsertionPoints().length, 2, "yes");
isEventChain(eventChain, [elemOne, elemThree, elemSix, shadowOne, elemTwo, elemFour, shadowTwo, elemFive], "Event path for test 2 for event dispatched on elemOne.");
/*
* Test 3: Test of event dispatch through nested ShadowRoot with content insertion points.
*
* <div elemOne> ------- <shadow-root shadowOne>
* | |
* <span elemTwo> <span elemThree> ------------ <shadow-root shadowTwo>
* | |
* <span elemFour> <content elemSix>
* |
* <content elemFive>
*/
elemOne = document.createElement("div");
elemOne.addEventListener("custom", eventListener);
elemTwo = document.createElement("span");
elemTwo.addEventListener("custom", eventListener);
elemThree = document.createElement("span");
elemThree.addEventListener("custom", eventListener);
elemFour = document.createElement("span");
elemFour.addEventListener("custom", eventListener);
elemFive = document.createElement("content");
elemFive.addEventListener("custom", eventListener);
elemSix = document.createElement("content");
elemSix.addEventListener("custom", eventListener);
shadowOne = elemOne.createShadowRoot();
shadowOne.addEventListener("custom", eventListener);
shadowTwo = elemThree.createShadowRoot();
shadowTwo.addEventListener("custom", eventListener);
elemOne.appendChild(elemTwo);
shadowOne.appendChild(elemThree);
elemThree.appendChild(elemFour);
elemFour.appendChild(elemFive);
shadowTwo.appendChild(elemSix);
eventChain = [];
customEvent = new CustomEvent("custom", { "bubbles" : true, "composed" : true });
elemTwo.dispatchEvent(customEvent);
isEventChain(eventChain, [elemTwo, elemFive, elemFour, elemSix, shadowTwo, elemThree, shadowOne, elemOne], "Event path for test 3 for event dispatched on elemTwo.");
/*
* Test 4: Test of event dispatch through host with multiple ShadowRoots with shadow insertion point.
*
* <div elemSeven> --- <shadow-root shadowTwo> (younger ShadowRoot)
* | | |
* <div elemOne> | <div elemSix> -------- <shadow-root shadowOne>
* | | |
* | <shadow elemFour> <content elemFive>
* | |
* | <content elemTwo>
* |
* --- <shadow-root shadowThree> (older ShadowRoot)
* | |
* | <content elemThree>
* |
* <div elemEight>
*/
elemOne = document.createElement("div");
elemOne.addEventListener("custom", eventListener);
elemTwo = document.createElement("content");
elemTwo.addEventListener("custom", eventListener);
elemThree = document.createElement("content");
elemThree.addEventListener("custom", eventListener);
elemFour = document.createElement("shadow");
elemFour.addEventListener("custom", eventListener);
elemFive = document.createElement("content");
elemFive.addEventListener("custom", eventListener);
elemSix = document.createElement("div");
elemSix.addEventListener("custom", eventListener);
var elemSeven = document.createElement("div");
elemSeven.addEventListener("custom", eventListener);
var elemEight = document.createElement("div");
elemEight.addEventListener("custom", eventListener);
var shadowThree = elemSeven.createShadowRoot();
shadowThree.addEventListener("custom", eventListener);
shadowTwo = elemSeven.createShadowRoot();
shadowTwo.addEventListener("custom", eventListener);
shadowOne = elemSix.createShadowRoot();
shadowOne.addEventListener("custom", eventListener);
elemSeven.appendChild(elemOne);
shadowTwo.appendChild(elemSix);
elemSix.appendChild(elemFour);
elemFour.appendChild(elemTwo);
shadowThree.appendChild(elemEight);
shadowThree.appendChild(elemThree);
shadowOne.appendChild(elemFive);
eventChain = [];
customEvent = new CustomEvent("custom", { "bubbles" : true, "composed" : true });
elemOne.dispatchEvent(customEvent);
isEventChain(eventChain, [elemOne, elemFive, shadowOne, elemThree, shadowThree, elemTwo, elemFour, elemSix, shadowTwo, elemSeven], "Event path for test 4 for event dispatched on elemOne.");
eventChain = [];
customEvent = new CustomEvent("custom", { "bubbles" : true, "composed" : true });
elemEight.dispatchEvent(customEvent);
isEventChain(eventChain, [elemEight, elemFive, shadowOne, elemSix, shadowTwo, elemSeven], "Event path for test 4 for event dispatched on elemEight.");
/*
* Test 5: Test of event dispatch through nested shadowroot with insertion points that match specific tags.
*
* <div elemOne> --------- <shadow-root shadowOne>
* | | |
* | <p elemThree> <span elemFour> ------------------------ <shadow-root shadowTwo>
* | | | |
* <span elemTwo> | <content select="p" elemFive> <content elemSeven>
* |
* <content select="span" elemSix>
*/
elemOne = document.createElement("div");
elemOne.addEventListener("custom", eventListener);
elemTwo = document.createElement("span");
elemTwo.addEventListener("custom", eventListener);
elemThree = document.createElement("p");
elemThree.addEventListener("custom", eventListener);
elemFour = document.createElement("span");
elemFour.addEventListener("custom", eventListener);
elemFive = document.createElement("content");
elemFive.select = "p";
elemFive.addEventListener("custom", eventListener);
elemSix = document.createElement("content");
elemSix.select = "span";
elemSix.addEventListener("custom", eventListener);
elemSeven = document.createElement("content");
elemSeven.addEventListener("custom", eventListener);
shadowTwo = elemFour.createShadowRoot();
shadowTwo.addEventListener("custom", eventListener);
shadowOne = elemOne.createShadowRoot();
shadowOne.addEventListener("custom", eventListener);
elemOne.appendChild(elemTwo);
elemOne.appendChild(elemThree);
shadowOne.appendChild(elemFour);
elemFour.appendChild(elemSix);
elemFour.appendChild(elemFive);
shadowTwo.appendChild(elemSeven);
eventChain = [];
customEvent = new CustomEvent("custom", { "bubbles" : true, "composed" : true });
elemTwo.dispatchEvent(customEvent);
isEventChain(eventChain, [elemTwo, elemSeven, shadowTwo, elemSix, elemFour, shadowOne, elemOne], "Event path for test 5 for event dispatched on elemTwo.");
eventChain = [];
customEvent = new CustomEvent("custom", { "bubbles" : true, "composed" : true });
elemThree.dispatchEvent(customEvent);
isEventChain(eventChain, [elemThree, elemSeven, shadowTwo, elemFive, elemFour, shadowOne, elemOne], "Event path for test 5 for event dispatched on elemThree.");
/*
* Test 6: Test of event dispatch through nested shadowroot with insertion points that match specific tags.
*
* <div elemOne> --------- <shadow-root shadowOne>;
* | | |
* | <p elemThree> <span elemFour> ------ <shadow-root shadowTwo>
* | | | |
* <span elemTwo> <content elemFive> | <content select="p" elemSeven>
* |
* <content select="span" elemSix>
*/
elemOne = document.createElement("div");
elemOne.addEventListener("custom", eventListener);
elemTwo = document.createElement("span");
elemTwo.addEventListener("custom", eventListener);
elemThree = document.createElement("p");
elemThree.addEventListener("custom", eventListener);
elemFour = document.createElement("span");
elemFour.addEventListener("custom", eventListener);
elemFive = document.createElement("content");
elemFive.addEventListener("custom", eventListener);
elemSix = document.createElement("content");
elemSix.select = "span";
elemSix.addEventListener("custom", eventListener);
elemSeven = document.createElement("content");
elemSeven.select = "p";
elemSeven.addEventListener("custom", eventListener);
shadowTwo = elemFour.createShadowRoot();
shadowTwo.addEventListener("custom", eventListener);
shadowOne = elemOne.createShadowRoot();
shadowOne.addEventListener("custom", eventListener);
elemOne.appendChild(elemTwo);
elemOne.appendChild(elemThree);
shadowOne.appendChild(elemFour);
elemFour.appendChild(elemFive);
shadowTwo.appendChild(elemSix);
shadowTwo.appendChild(elemSeven);
eventChain = [];
customEvent = new CustomEvent("custom", { "bubbles" : true, "composed" : true });
elemTwo.dispatchEvent(customEvent);
isEventChain(eventChain, [elemTwo, elemSix, shadowTwo, elemFive, elemFour, shadowOne, elemOne], "Event path for test 6 for event dispatched on elemTwo.");
eventChain = [];
customEvent = new CustomEvent("custom", { "bubbles" : true, "composed" : true });
elemThree.dispatchEvent(customEvent);
isEventChain(eventChain, [elemThree, elemSeven, shadowTwo, elemFive, elemFour, shadowOne, elemOne], "Event path for test 6 for event dispatched on elemThree.");
/*
* Test 7: Test of event dispatch through nested shadowroot with insertion points that match specific tags.
*
* <div elemOne> --------- <shadow-root shadowOne>
* | | |
* | <p elemThree> <span elemFour> ------ <shadow-root shadowTwo>
* | | |
* <span elemTwo> <content elemFive> <span elemEight>
* | |
* | <content select="p" elemSeven>
* |
* <content select="span" elemSix>
*/
elemOne = document.createElement("div");
elemOne.addEventListener("custom", eventListener);
elemTwo = document.createElement("span");
elemTwo.addEventListener("custom", eventListener);
elemThree = document.createElement("p");
elemThree.addEventListener("custom", eventListener);
elemFour = document.createElement("span");
elemFour.addEventListener("custom", eventListener);
elemFive = document.createElement("content");
elemFive.addEventListener("custom", eventListener);
elemSix = document.createElement("content");
elemSix.select = "span";
elemSix.addEventListener("custom", eventListener);
elemSeven = document.createElement("content");
elemSeven.select = "p";
elemSeven.addEventListener("custom", eventListener);
elemEight = document.createElement("span");
elemEight.addEventListener("custom", eventListener);
shadowTwo = elemFour.createShadowRoot();
shadowTwo.addEventListener("custom", eventListener);
shadowOne = elemOne.createShadowRoot();
shadowOne.addEventListener("custom", eventListener);
elemOne.appendChild(elemTwo);
elemOne.appendChild(elemThree);
shadowOne.appendChild(elemFour);
elemFour.appendChild(elemFive);
shadowTwo.appendChild(elemEight);
elemEight.appendChild(elemSix);
elemEight.appendChild(elemSeven);
eventChain = [];
customEvent = new CustomEvent("custom", { "bubbles" : true, "composed" : true });
elemTwo.dispatchEvent(customEvent);
isEventChain(eventChain, [elemTwo, elemSix, elemEight, shadowTwo, elemFive, elemFour, shadowOne, elemOne], "Event path for test 7 for event dispatched on elemTwo.");
eventChain = [];
customEvent = new CustomEvent("custom", { "bubbles" : true, "composed" : true });
elemThree.dispatchEvent(customEvent);
isEventChain(eventChain, [elemThree, elemSeven, elemEight, shadowTwo, elemFive, elemFour, shadowOne, elemOne], "Event path for test 7 for event dispatched on elemThree.");
/*
* Test 8: Test of event dispatch through host with multiple ShadowRoots with shadow insertion point.
*
* <div elemOne> --- <shadow-root shadowOne> (younger ShadowRoot)
* | |
* | <div elemFour>
* | |
* | <shadow elemTwo>
* |
* --- <shadow-root shadowTwo> (older ShadowRoot)
* |
* <div elemThree>
*/
elemOne = document.createElement("div");
elemOne.addEventListener("custom", eventListener);
elemTwo = document.createElement("shadow");
elemTwo.addEventListener("custom", eventListener);
elemThree = document.createElement("div");
elemThree.addEventListener("custom", eventListener);
elemFour = document.createElement("div");
elemFour.addEventListener("custom", eventListener);
shadowTwo = elemOne.createShadowRoot();
shadowTwo.addEventListener("custom", eventListener);
shadowOne = elemOne.createShadowRoot();
shadowOne.addEventListener("custom", eventListener);
shadowOne.appendChild(elemFour);
elemFour.appendChild(elemTwo);
shadowTwo.appendChild(elemThree);
eventChain = [];
customEvent = new CustomEvent("custom", { "bubbles" : true, "composed" : true });
elemThree.dispatchEvent(customEvent);
isEventChain(eventChain, [elemThree, shadowTwo, elemTwo, elemFour, shadowOne, elemOne], "Event path for test 8 for event dispatched on elemThree.");
</script>
</body>
</html>

Просмотреть файл

@ -1,41 +0,0 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=1083587
-->
<head>
<meta charset="utf-8">
<title>Test for Bug 1083587</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1083587">Mozilla Bug 1083587</a>
<p id="display"></p>
<div id="content" style="display: none">
<div id="host"></div>
</div>
<pre id="test">
</pre>
<script type="application/javascript">
/** Test for Bug 1083587 **/
var hostInDoc = document.getElementById("host");
var shadowOne = hostInDoc.createShadowRoot();
is(shadowOne.host, hostInDoc);
var shadowTwo = hostInDoc.createShadowRoot();
is(shadowOne.host, hostInDoc);
is(shadowTwo.host, hostInDoc);
var hostNotInDoc = document.createElement("div");
var shadowThree = hostNotInDoc.createShadowRoot();
is(shadowThree.host, hostNotInDoc);
var shadowFour = hostNotInDoc.createShadowRoot();
is(shadowThree.host, hostNotInDoc);
is(shadowFour.host, hostNotInDoc);
</script>
</body>
</html>

Просмотреть файл

@ -1,57 +0,0 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=806506
-->
<head>
<title>Test for ShadowRoot styles with multiple ShadowRoot on host.</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<div class="tall" id="bodydiv"></div>
<div id="container"></div>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=806506">Bug 806506</a>
<script>
// Create ShadowRoot.
var container = document.getElementById("container");
var elem = document.createElement("div");
container.appendChild(elem); // Put ShadowRoot host in document.
var firstRoot = elem.createShadowRoot();
var secondRoot = elem.createShadowRoot();
var thirdRoot = elem.createShadowRoot();
// A style element that will be appended into the ShadowRoot.
var firstStyle = document.createElement("style");
firstRoot.appendChild(firstStyle);
is(firstRoot.styleSheets.length, 1, "firstStyle should be the only style in firstRoot.");
is(firstRoot.styleSheets[0].ownerNode, firstStyle, "firstStyle should in the ShadowRoot styleSheets.");
var secondStyle = document.createElement("style");
secondRoot.appendChild(secondStyle);
is(secondRoot.styleSheets.length, 1, "secondStyle should be the only style in secondRoot.");
is(secondRoot.styleSheets[0].ownerNode, secondStyle, "secondStyle should in the ShadowRoot styleSheets.");
var thirdStyle = document.createElement("style");
thirdRoot.appendChild(thirdStyle);
is(thirdRoot.styleSheets.length, 1, "thirdStyle should be the only style in thirdRoot.");
is(thirdRoot.styleSheets[0].ownerNode, thirdStyle, "thirdStyle should in the ShadowRoot styleSheets.");
// Check the stylesheet counts again to make sure that none of the style sheets leaked into the older ShadowRoots.
is(firstRoot.styleSheets.length, 1, "Adding a stylesheet to a younger ShadowRoot should not affect stylesheets in the older ShadowRoot.");
is(secondRoot.styleSheets.length, 1, "Adding a stylesheet to a younger ShadowRoot should not affect stylesheets in the older ShadowRoot.");
// Remove styles and make sure they are removed from the correct ShadowRoot.
firstRoot.removeChild(firstStyle);
is(firstRoot.styleSheets.length, 0, "firstRoot should no longer have any styles.");
thirdRoot.removeChild(thirdStyle);
is(thirdRoot.styleSheets.length, 0, "thirdRoot should no longer have any styles.");
secondRoot.removeChild(secondStyle);
is(secondRoot.styleSheets.length, 0, "secondRoot should no longer have any styles.");
</script>
</body>
</html>

Просмотреть файл

@ -1,41 +0,0 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=1083587
-->
<head>
<meta charset="utf-8">
<title>Test for Bug 1083587</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1083587">Mozilla Bug 1083587</a>
<p id="display"></p>
<div id="content" style="display: none">
<div id="host"></div>
</div>
<pre id="test">
</pre>
<script type="application/javascript">
/** Test for Bug 1083587 **/
var hostInDoc = document.getElementById("host");
var shadowOne = hostInDoc.createShadowRoot();
is(shadowOne.olderShadowRoot, null);
var shadowTwo = hostInDoc.createShadowRoot();
is(shadowOne.olderShadowRoot, null);
is(shadowTwo.olderShadowRoot, shadowOne);
var hostNotInDoc = document.createElement("div");
var shadowThree = hostNotInDoc.createShadowRoot();
is(shadowThree.olderShadowRoot, null);
var shadowFour = hostNotInDoc.createShadowRoot();
is(shadowThree.olderShadowRoot, null);
is(shadowFour.olderShadowRoot, shadowThree);
</script>
</body>
</html>

Просмотреть файл

@ -1,19 +0,0 @@
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/.
*
* The origin of this IDL file is
* https://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/shadow/index.html
*
* © Copyright 2004-2011 Apple Computer, Inc., Mozilla Foundation, and
* Opera Software ASA. You are granted a license to use, reproduce
* and create derivative works of this document.
*/
[Func="nsDocument::IsWebComponentsEnabled"]
interface HTMLShadowElement : HTMLElement
{
readonly attribute ShadowRoot? olderShadowRoot;
};

Просмотреть файл

@ -20,7 +20,6 @@ interface ShadowRoot : DocumentFragment
[CEReactions, SetterThrows, TreatNullAs=EmptyString]
attribute DOMString innerHTML;
readonly attribute Element host;
readonly attribute ShadowRoot? olderShadowRoot;
attribute boolean applyAuthorStyles;
readonly attribute StyleSheetList styleSheets;
};

Просмотреть файл

@ -520,12 +520,10 @@ partial interface Window {
[Func="IsChromeOrXBL"]
sequence<DOMString> getRegionalPrefsLocales();
#ifdef ENABLE_INTL_API
/**
* Getter funcion for IntlUtils, which provides helper functions for
* localization.
*/
[Throws, Func="IsChromeOrXBL"]
readonly attribute IntlUtils intlUtils;
#endif
};

Просмотреть файл

@ -616,7 +616,6 @@ WEBIDL_FILES = [
'HTMLQuoteElement.webidl',
'HTMLScriptElement.webidl',
'HTMLSelectElement.webidl',
'HTMLShadowElement.webidl',
'HTMLSourceElement.webidl',
'HTMLSpanElement.webidl',
'HTMLStyleElement.webidl',
@ -656,6 +655,7 @@ WEBIDL_FILES = [
'InputEvent.webidl',
'InspectorUtils.webidl',
'IntersectionObserver.webidl',
'IntlUtils.webidl',
'IterableIterator.webidl',
'KeyAlgorithm.webidl',
'KeyboardEvent.webidl',
@ -1144,8 +1144,3 @@ if CONFIG['ACCESSIBILITY']:
WEBIDL_FILES += [
'AccessibleNode.webidl',
]
if CONFIG['ENABLE_INTL_API']:
WEBIDL_FILES += [
'IntlUtils.webidl',
]

Просмотреть файл

@ -720,7 +720,6 @@ static const ElementInfo kElements[eHTMLTag_userdefined] = {
GROUP_LEAF),
ELEM(section, true, true, GROUP_BLOCK, GROUP_FLOW_ELEMENT),
ELEM(select, true, false, GROUP_FORMCONTROL, GROUP_SELECT_CONTENT),
ELEM(shadow, true, false, GROUP_NONE, GROUP_INLINE_ELEMENT),
ELEM(small, true, true, GROUP_FONTSTYLE, GROUP_INLINE_ELEMENT),
ELEM(source, false, false, GROUP_PICTURE_CONTENT, GROUP_NONE),
ELEM(span, true, true, GROUP_SPECIAL, GROUP_INLINE_ELEMENT),

Просмотреть файл

@ -31,7 +31,7 @@ DIRS += [
if CONFIG['MOZ_ENABLE_SKIA']:
DIRS += ['skia']
if CONFIG['MOZ_ENABLE_SKIA_PDF_SFNTLY'] and CONFIG['ENABLE_INTL_API']:
if CONFIG['MOZ_ENABLE_SKIA_PDF_SFNTLY']:
DIRS += ['sfntly/cpp/src']
if CONFIG['ENABLE_TESTS']:

Просмотреть файл

@ -101,7 +101,7 @@ elif CONFIG['CPU_ARCH'] == 'aarch64' and CONFIG['GNU_CC']:
DEFINES['SKIA_IMPLEMENTATION'] = 1
if CONFIG['MOZ_ENABLE_SKIA_PDF_SFNTLY'] and CONFIG['ENABLE_INTL_API']:
if CONFIG['MOZ_ENABLE_SKIA_PDF_SFNTLY']:
DEFINES['SK_PDF_USE_SFNTLY'] = 1
if not CONFIG['MOZ_ENABLE_SKIA_GPU']:

Просмотреть файл

@ -743,7 +743,7 @@ elif CONFIG['CPU_ARCH'] == 'aarch64' and CONFIG['GNU_CC']:
DEFINES['SKIA_IMPLEMENTATION'] = 1
if CONFIG['MOZ_ENABLE_SKIA_PDF_SFNTLY'] and CONFIG['ENABLE_INTL_API']:
if CONFIG['MOZ_ENABLE_SKIA_PDF_SFNTLY']:
DEFINES['SK_PDF_USE_SFNTLY'] = 1
if not CONFIG['MOZ_ENABLE_SKIA_GPU']:

Просмотреть файл

@ -86,6 +86,30 @@ ComputeImageFlags(ImageURL* uri, const nsCString& aMimeType, bool isMultiPart)
return imageFlags;
}
#ifdef DEBUG
static void
NotifyImageLoading(ImageURL* aURI)
{
if (!NS_IsMainThread()) {
RefPtr<ImageURL> uri(aURI);
nsCOMPtr<nsIRunnable> ev =
NS_NewRunnableFunction("NotifyImageLoading", [uri] () -> void {
NotifyImageLoading(uri);
});
SystemGroup::Dispatch(TaskCategory::Other, ev.forget());
return;
}
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
NS_WARNING_ASSERTION(obs, "Can't get an observer service handle");
if (obs) {
nsAutoCString spec;
aURI->GetSpec(spec);
obs->NotifyObservers(nullptr, "image-loading", NS_ConvertUTF8toUTF16(spec).get());
}
}
#endif
/* static */ already_AddRefed<Image>
ImageFactory::CreateImage(nsIRequest* aRequest,
ProgressTracker* aProgressTracker,
@ -102,14 +126,10 @@ ImageFactory::CreateImage(nsIRequest* aRequest,
#ifdef DEBUG
// Record the image load for startup performance testing.
if (NS_IsMainThread()) {
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
NS_WARNING_ASSERTION(obs, "Can't get an observer service handle");
if (obs) {
nsAutoCString spec;
aURI->GetSpec(spec);
obs->NotifyObservers(nullptr, "image-loading", NS_ConvertUTF8toUTF16(spec).get());
}
bool match = false;
if ((NS_SUCCEEDED(aURI->SchemeIs("resource", &match)) && match) ||
(NS_SUCCEEDED(aURI->SchemeIs("chrome", &match)) && match)) {
NotifyImageLoading(aURI);
}
#endif

Просмотреть файл

@ -1700,6 +1700,12 @@ RasterImage::NotifyDrawingObservers()
return;
}
bool match = false;
if ((NS_FAILED(mURI->SchemeIs("resource", &match)) || !match) &&
(NS_FAILED(mURI->SchemeIs("chrome", &match)) || !match)) {
return;
}
// Record the image drawing for startup performance testing.
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
NS_WARNING_ASSERTION(obs, "Can't get an observer service handle");

Просмотреть файл

@ -459,13 +459,26 @@ imgRequest::GetCurrentURI(nsIURI** aURI)
}
bool
imgRequest::IsChrome() const
imgRequest::IsScheme(const char* aScheme) const
{
bool isChrome = false;
if (NS_WARN_IF(NS_FAILED(mURI->SchemeIs("chrome", &isChrome)))) {
MOZ_ASSERT(aScheme);
bool isScheme = false;
if (NS_WARN_IF(NS_FAILED(mURI->SchemeIs(aScheme, &isScheme)))) {
return false;
}
return isChrome;
return isScheme;
}
bool
imgRequest::IsChrome() const
{
return IsScheme("chrome");
}
bool
imgRequest::IsData() const
{
return IsScheme("data");
}
nsresult
@ -819,13 +832,17 @@ imgRequest::OnStartRequest(nsIRequest* aRequest, nsISupports* ctxt)
this->Cancel(NS_IMAGELIB_ERROR_FAILURE);
}
// Try to retarget OnDataAvailable to a decode thread.
nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aRequest);
// Try to retarget OnDataAvailable to a decode thread. We must process data
// URIs synchronously as per the spec however.
if (!channel || IsData()) {
return NS_OK;
}
nsCOMPtr<nsIThreadRetargetableRequest> retargetable =
do_QueryInterface(aRequest);
if (httpChannel && retargetable) {
if (retargetable) {
nsAutoCString mimeType;
nsresult rv = httpChannel->GetContentType(mimeType);
nsresult rv = channel->GetContentType(mimeType);
if (NS_SUCCEEDED(rv) && !mimeType.EqualsLiteral(IMAGE_SVG_XML)) {
// Retarget OnDataAvailable to the DecodePool's IO thread.
nsCOMPtr<nsIEventTarget> target =

Просмотреть файл

@ -153,7 +153,9 @@ public:
// OK to use on any thread.
nsresult GetURI(ImageURL** aURI);
nsresult GetCurrentURI(nsIURI** aURI);
bool IsScheme(const char* aScheme) const;
bool IsChrome() const;
bool IsData() const;
nsresult GetImageErrorCode(void);

Просмотреть файл

@ -556,10 +556,8 @@ GetClass(uint32_t u)
/* ZWJ = 42, [ZWJ]*/ CLASS_CHARACTER
};
#if ENABLE_INTL_API
static_assert(U_LB_COUNT == mozilla::ArrayLength(sUnicodeLineBreakToClass),
"Gecko vs ICU LineBreak class mismatch");
#endif
auto cls = mozilla::unicode::GetLineBreakClass(u);
MOZ_ASSERT(cls < mozilla::ArrayLength(sUnicodeLineBreakToClass));

Просмотреть файл

@ -9,6 +9,10 @@
# read from the Unicode Character Database and compiled into multi-level arrays
# for efficient lookup.
#
# Note that for most properties, we now rely on ICU; this tool and the tables
# it generates are used only for a couple of properties not readily exposed
# via ICU APIs.
#
# To regenerate the tables in nsUnicodePropertyData.cpp:
#
# (1) Download the current Unicode data files from
@ -17,13 +21,6 @@
#
# NB: not all the files are actually needed; currently, we require
# - UnicodeData.txt
# - Scripts.txt
# - BidiMirroring.txt
# - BidiBrackets.txt
# - HangulSyllableType.txt
# - LineBreak.txt
# - EastAsianWidth.txt
# - DerivedCoreProperties.txt
# - ReadMe.txt (to record version/date of the UCD)
# - Unihan_Variants.txt (from Unihan.zip)
# though this may change if we find a need for additional properties.
@ -44,7 +41,6 @@
# (2) Run this tool using a command line of the form
#
# perl genUnicodePropertyData.pl \
# /path/to/harfbuzz/src \
# /path/to/icu/common/unicode \
# /path/to/UCD-directory
#
@ -58,17 +54,15 @@
use strict;
use List::Util qw(first);
if ($#ARGV != 2) {
if ($#ARGV != 1) {
print <<__EOT;
# Run this tool using a command line of the form
#
# perl genUnicodePropertyData.pl \\
# /path/to/harfbuzz/src \\
# /path/to/icu/common/unicode \\
# /path/to/UCD-directory
#
# where harfbuzz/src is the directory containing harfbuzz .cc and .hh files,
# icu/common/unicode is the directory containing ICU 'common' public headers,
# where icu/common/unicode is the directory containing ICU 'common' headers,
# and UCD-directory is a directory containing the current Unicode Character
# Database files (UnicodeData.txt, etc), available from
# http://www.unicode.org/Public/UNIDATA/, with additional resources as
@ -84,35 +78,11 @@ __EOT
exit 0;
}
my $HARFBUZZ = $ARGV[0];
my $ICU = $ARGV[1];
my $UNICODE = $ARGV[2];
my $ICU = $ARGV[0];
my $UNICODE = $ARGV[1];
# load HB_Category constants
my $cc = -1;
my %catCode;
sub readHarfBuzzHeader
{
my $file = shift;
open FH, "< $HARFBUZZ/$file" or die "can't open harfbuzz header $HARFBUZZ/$file\n";
while (<FH>) {
if (m/HB_UNICODE_GENERAL_CATEGORY_([A-Z_]+)/) {
$cc++;
$catCode{$1} = $cc;
}
}
close FH;
}
&readHarfBuzzHeader("hb-unicode.h");
die "didn't find HarfBuzz category codes\n" if $cc == -1;
my %scriptCode;
my @scriptCodeToTag;
my @scriptCodeToName;
my @idtype;
my $sc = -1;
@ -129,8 +99,6 @@ sub readIcuHeader
s/SIGN_WRITING/SIGNWRITING/;
if (m|USCRIPT_([A-Z_]+)\s*=\s*([0-9]+),\s*/\*\s*([A-Z][a-z]{3})\s*\*/|) {
$sc = $2;
$scriptCode{$1} = $sc;
$scriptCodeToTag[$sc] = $3;
$scriptCodeToName[$sc] = $1;
}
}
@ -170,32 +138,6 @@ my %mappedIdType = (
"Allowed" => 1
);
my %bidicategoryCode = (
"L" => 0, # Left-to-Right
"R" => 1, # Right-to-Left
"EN" => 2, # European Number
"ES" => 3, # European Number Separator
"ET" => 4, # European Number Terminator
"AN" => 5, # Arabic Number
"CS" => 6, # Common Number Separator
"B" => 7, # Paragraph Separator
"S" => 8, # Segment Separator
"WS" => 9, # Whitespace
"ON" => 10, # Other Neutrals
"LRE" => 11, # Left-to-Right Embedding
"LRO" => 12, # Left-to-Right Override
"AL" => 13, # Right-to-Left Arabic
"RLE" => 14, # Right-to-Left Embedding
"RLO" => 15, # Right-to-Left Override
"PDF" => 16, # Pop Directional Format
"NSM" => 17, # Non-Spacing Mark
"BN" => 18, # Boundary Neutral
"FSI" => 19, # First Strong Isolate
"LRI" => 20, # Left-to-Right Isolate
"RLI" => 21, # Right-to-left Isolate
"PDI" => 22 # Pop Direcitonal Isolate
);
my %verticalOrientationCode = (
'U' => 0, # U - Upright, the same orientation as in the code charts
'R' => 1, # R - Rotated 90 degrees clockwise compared to the code charts
@ -203,141 +145,18 @@ my %verticalOrientationCode = (
'Tr' => 3 # Tr - Transformed typographically, with fallback to Rotated
);
my %lineBreakCode = ( # ordering matches ICU's ULineBreak enum
"XX" => 0,
"AI" => 1,
"AL" => 2,
"B2" => 3,
"BA" => 4,
"BB" => 5,
"BK" => 6,
"CB" => 7,
"CL" => 8,
"CM" => 9,
"CR" => 10,
"EX" => 11,
"GL" => 12,
"HY" => 13,
"ID" => 14,
"IN" => 15,
"IS" => 16,
"LF" => 17,
"NS" => 18,
"NU" => 19,
"OP" => 20,
"PO" => 21,
"PR" => 22,
"QU" => 23,
"SA" => 24,
"SG" => 25,
"SP" => 26,
"SY" => 27,
"ZW" => 28,
"NL" => 29,
"WJ" => 30,
"H2" => 31,
"H3" => 32,
"JL" => 33,
"JT" => 34,
"JV" => 35,
"CP" => 36,
"CJ" => 37,
"HL" => 38,
"RI" => 39,
"EB" => 40,
"EM" => 41,
"ZWJ" => 42
);
my %eastAsianWidthCode = (
"N" => 0,
"A" => 1,
"H" => 2,
"W" => 3,
"F" => 4,
"Na" => 5
);
# initialize default properties
my @script;
my @category;
my @combining;
my @mirror;
my @pairedBracketType;
my @hangul;
my @casemap;
my @idtype;
my @numericvalue;
my @hanVariant;
my @bidicategory;
my @fullWidth;
my @fullWidthInverse;
my @verticalOrientation;
my @lineBreak;
my @eastAsianWidthFWH;
my @defaultIgnorable;
for (my $i = 0; $i < 0x110000; ++$i) {
$script[$i] = $scriptCode{"UNKNOWN"};
$category[$i] = $catCode{"UNASSIGNED"};
$combining[$i] = 0;
$pairedBracketType[$i] = 0;
$casemap[$i] = 0;
$idtype[$i] = $mappedIdType{'Restricted'};
$numericvalue[$i] = -1;
$hanVariant[$i] = 0;
$bidicategory[$i] = $bidicategoryCode{"L"};
$fullWidth[$i] = 0;
$fullWidthInverse[$i] = 0;
$verticalOrientation[$i] = 1; # default for unlisted codepoints is 'R'
$lineBreak[$i] = $lineBreakCode{"XX"};
$eastAsianWidthFWH[$i] = 0;
$defaultIgnorable[$i] = 0;
}
# blocks where the default for bidi category is not L
for my $i (0x0600..0x07BF, 0x08A0..0x08FF, 0xFB50..0xFDCF, 0xFDF0..0xFDFF, 0xFE70..0xFEFF, 0x1EE00..0x0001EEFF) {
$bidicategory[$i] = $bidicategoryCode{"AL"};
}
for my $i (0x0590..0x05FF, 0x07C0..0x089F, 0xFB1D..0xFB4F, 0x00010800..0x00010FFF, 0x0001E800..0x0001EDFF, 0x0001EF00..0x0001EFFF) {
$bidicategory[$i] = $bidicategoryCode{"R"};
}
for my $i (0x20A0..0x20CF) {
$bidicategory[$i] = $bidicategoryCode{"ET"};
}
my %ucd2hb = (
'Cc' => 'CONTROL',
'Cf' => 'FORMAT',
'Cn' => 'UNASSIGNED',
'Co' => 'PRIVATE_USE',
'Cs' => 'SURROGATE',
'Ll' => 'LOWERCASE_LETTER',
'Lm' => 'MODIFIER_LETTER',
'Lo' => 'OTHER_LETTER',
'Lt' => 'TITLECASE_LETTER',
'Lu' => 'UPPERCASE_LETTER',
'Mc' => 'SPACING_MARK',
'Me' => 'ENCLOSING_MARK',
'Mn' => 'NON_SPACING_MARK',
'Nd' => 'DECIMAL_NUMBER',
'Nl' => 'LETTER_NUMBER',
'No' => 'OTHER_NUMBER',
'Pc' => 'CONNECT_PUNCTUATION',
'Pd' => 'DASH_PUNCTUATION',
'Pe' => 'CLOSE_PUNCTUATION',
'Pf' => 'FINAL_PUNCTUATION',
'Pi' => 'INITIAL_PUNCTUATION',
'Po' => 'OTHER_PUNCTUATION',
'Ps' => 'OPEN_PUNCTUATION',
'Sc' => 'CURRENCY_SYMBOL',
'Sk' => 'MODIFIER_SYMBOL',
'Sm' => 'MATH_SYMBOL',
'So' => 'OTHER_SYMBOL',
'Zl' => 'LINE_SEPARATOR',
'Zp' => 'PARAGRAPH_SEPARATOR',
'Zs' => 'SPACE_SEPARATOR'
);
# read ReadMe.txt
my @versionInfo;
open FH, "< $UNICODE/ReadMe.txt" or die "can't open Unicode ReadMe.txt file\n";
@ -347,12 +166,6 @@ while (<FH>) {
}
close FH;
my $kTitleToUpper = 0x80000000;
my $kUpperToLower = 0x40000000;
my $kLowerToTitle = 0x20000000;
my $kLowerToUpper = 0x10000000;
my $kCaseMapCharMask = 0x001fffff;
# read UnicodeData.txt
open FH, "< $UNICODE/UnicodeData.txt" or die "can't open UCD file UnicodeData.txt\n";
while (<FH>) {
@ -365,12 +178,6 @@ while (<FH>) {
if ($fields[1] =~ /Last/) {
my $last = hex "0x$fields[0]";
do {
$category[$first] = $catCode{$ucd2hb{$fields[2]}};
$combining[$first] = $fields[3];
$bidicategory[$first] = $bidicategoryCode{$fields[4]};
unless (length($fields[7]) == 0) {
$numericvalue[$first] = $fields[7];
}
if ($fields[1] =~ /CJK/) {
@hanVariant[$first] = 3;
}
@ -381,33 +188,6 @@ while (<FH>) {
}
} else {
my $usv = hex "0x$fields[0]";
$category[$usv] = $catCode{$ucd2hb{$fields[2]}};
$combining[$usv] = $fields[3];
my $upper = hex $fields[12];
my $lower = hex $fields[13];
my $title = hex $fields[14];
# we only store one mapping for each character,
# but also record what kind of mapping it is
if ($upper && $lower) {
$casemap[$usv] |= $kTitleToUpper;
$casemap[$usv] |= ($usv ^ $upper);
}
elsif ($lower) {
$casemap[$usv] |= $kUpperToLower;
$casemap[$usv] |= ($usv ^ $lower);
}
elsif ($title && ($title != $upper)) {
$casemap[$usv] |= $kLowerToTitle;
$casemap[$usv] |= ($usv ^ $title);
}
elsif ($upper) {
$casemap[$usv] |= $kLowerToUpper;
$casemap[$usv] |= ($usv ^ $upper);
}
$bidicategory[$usv] = $bidicategoryCode{$fields[4]};
unless (length($fields[7]) == 0) {
$numericvalue[$usv] = $fields[7];
}
if ($fields[1] =~ /CJK/) {
@hanVariant[$usv] = 3;
}
@ -427,178 +207,6 @@ while (<FH>) {
}
close FH;
# read Scripts.txt
open FH, "< $UNICODE/Scripts.txt" or die "can't open UCD file Scripts.txt\n";
push @versionInfo, "";
while (<FH>) {
chomp;
push @versionInfo, $_;
last if /Date:/;
}
while (<FH>) {
if (m/([0-9A-F]{4,6})(?:\.\.([0-9A-F]{4,6}))*\s+;\s+([^ ]+)/) {
my $script = uc($3);
unless (exists $scriptCode{$script}) {
warn "unknown ICU script $script";
$scriptCode{$script} = $scriptCode{"UNKNOWN"};
}
$script = $scriptCode{$script};
my $start = hex "0x$1";
my $end = (defined $2) ? hex "0x$2" : $start;
for (my $i = $start; $i <= $end; ++$i) {
$script[$i] = $script;
}
}
}
close FH;
# read BidiMirroring.txt
my @offsets = ();
push @offsets, 0;
open FH, "< $UNICODE/BidiMirroring.txt" or die "can't open UCD file BidiMirroring.txt\n";
push @versionInfo, "";
while (<FH>) {
chomp;
push @versionInfo, $_;
last if /Date:/;
}
while (<FH>) {
s/#.*//;
if (m/([0-9A-F]{4,6});\s*([0-9A-F]{4,6})/) {
my $mirrorOffset = hex("0x$2") - hex("0x$1");
my $offsetIndex = first { $offsets[$_] eq $mirrorOffset } 0..$#offsets;
if ($offsetIndex == undef) {
die "too many offset codes\n" if scalar @offsets == 31;
push @offsets, $mirrorOffset;
$offsetIndex = $#offsets;
}
$mirror[hex "0x$1"] = $offsetIndex;
}
}
close FH;
# read BidiBrackets.txt
my %pairedBracketTypeCode = (
'N' => 0,
'O' => 1,
'C' => 2
);
open FH, "< $UNICODE/BidiBrackets.txt" or die "can't open UCD file BidiBrackets.txt\n";
push @versionInfo, "";
while (<FH>) {
chomp;
push @versionInfo, $_;
last if /Date:/;
}
while (<FH>) {
s/#.*//;
if (m/([0-9A-F]{4,6});\s*([0-9A-F]{4,6});\s*(.)/) {
my $mirroredChar = $offsets[$mirror[hex "0x$1"]] + hex "0x$1";
die "bidi bracket does not match mirrored char\n" unless $mirroredChar == hex "0x$2";
my $pbt = uc($3);
warn "unknown Bidi Bracket type" unless exists $pairedBracketTypeCode{$pbt};
$pairedBracketType[hex "0x$1"] = $pairedBracketTypeCode{$pbt};
}
}
close FH;
# read HangulSyllableType.txt
my %hangulType = (
'L' => 0x01,
'V' => 0x02,
'T' => 0x04,
'LV' => 0x03,
'LVT' => 0x07
);
open FH, "< $UNICODE/HangulSyllableType.txt" or die "can't open UCD file HangulSyllableType.txt\n";
push @versionInfo, "";
while (<FH>) {
chomp;
push @versionInfo, $_;
last if /Date:/;
}
while (<FH>) {
s/#.*//;
if (m/([0-9A-F]{4,6})(?:\.\.([0-9A-F]{4,6}))*\s*;\s*([^ ]+)/) {
my $hangul = uc($3);
warn "unknown Hangul syllable type" unless exists $hangulType{$hangul};
$hangul = $hangulType{$hangul};
my $start = hex "0x$1";
my $end = (defined $2) ? hex "0x$2" : $start;
for (my $i = $start; $i <= $end; ++$i) {
$hangul[$i] = $hangul;
}
}
}
close FH;
# read LineBreak.txt
open FH, "< $UNICODE/LineBreak.txt" or die "can't open UCD file LineBreak.txt\n";
push @versionInfo, "";
while (<FH>) {
chomp;
push @versionInfo, $_;
last if /Date:/;
}
while (<FH>) {
s/#.*//;
if (m/([0-9A-F]{4,6})(?:\.\.([0-9A-F]{4,6}))*\s*;\s*([^ ]+)/) {
my $lb = uc($3);
warn "unknown LineBreak class" unless exists $lineBreakCode{$lb};
$lb = $lineBreakCode{$lb};
my $start = hex "0x$1";
my $end = (defined $2) ? hex "0x$2" : $start;
for (my $i = $start; $i <= $end; ++$i) {
$lineBreak[$i] = $lb;
}
}
}
close FH;
# read EastAsianWidth.txt
open FH, "< $UNICODE/EastAsianWidth.txt" or die "can't open UCD file EastAsianWidth.txt\n";
push @versionInfo, "";
while (<FH>) {
chomp;
push @versionInfo, $_;
last if /Date:/;
}
while (<FH>) {
s/#.*//;
if (m/([0-9A-F]{4,6})(?:\.\.([0-9A-F]{4,6}))*\s*;\s*([^ ]+)/) {
my $start = hex "0x$1";
my $end = (defined $2) ? hex "0x$2" : $start;
my $eaw = $3;
warn "unknown EastAsianWidth class" unless exists $eastAsianWidthCode{$eaw};
my $isFWH = ($eaw =~ m/^[FWH]$/) ? 1 : 0;
for (my $i = $start; $i <= $end; ++$i) {
$eastAsianWidthFWH[$i] = $isFWH;
}
}
}
close FH;
# read DerivedCoreProperties.txt (for Default-Ignorables)
open FH, "< $UNICODE/DerivedCoreProperties.txt" or die "can't open UCD file DerivedCoreProperties.txt\n";
push @versionInfo, "";
while (<FH>) {
chomp;
push @versionInfo, $_;
last if /Date:/;
}
while (<FH>) {
s/#.*//;
if (m/([0-9A-F]{4,6})(?:\.\.([0-9A-F]{4,6}))*\s*;\s*Default_Ignorable_Code_Point/) {
my $start = hex "0x$1";
my $end = (defined $2) ? hex "0x$2" : $start;
for (my $i = $start; $i <= $end; ++$i) {
$defaultIgnorable[$i] = 1;
}
}
}
close FH;
# read IdentifierStatus.txt
open FH, "< $UNICODE/security/IdentifierStatus.txt" or die "can't open UCD file IdentifierStatus.txt\n";
push @versionInfo, "";
@ -735,50 +343,17 @@ $versionInfo
__END
print DATA_TABLES "#if !ENABLE_INTL_API\n";
print DATA_TABLES "static const uint32_t sScriptCodeToTag[] = {\n";
for (my $i = 0; $i < scalar @scriptCodeToTag; ++$i) {
printf DATA_TABLES " HB_TAG('%c','%c','%c','%c')", unpack('cccc', $scriptCodeToTag[$i]);
print DATA_TABLES $i < $#scriptCodeToTag ? ",\n" : "\n";
}
print DATA_TABLES "};\n";
print DATA_TABLES "#endif\n\n";
our $totalData = 0;
print DATA_TABLES "#if !ENABLE_INTL_API\n";
print DATA_TABLES "static const int16_t sMirrorOffsets[] = {\n";
for (my $i = 0; $i < scalar @offsets; ++$i) {
printf DATA_TABLES " $offsets[$i]";
print DATA_TABLES $i < $#offsets ? ",\n" : "\n";
}
print DATA_TABLES "};\n";
print DATA_TABLES "#endif\n\n";
print HEADER "#pragma pack(1)\n\n";
sub sprintCharProps1
{
my $usv = shift;
return sprintf("{%d,%d,%d}, ", $mirror[$usv], $hangul[$usv], $combining[$usv]);
}
my $type = q/
struct nsCharProps1 {
unsigned char mMirrorOffsetIndex:5;
unsigned char mHangulType:3;
unsigned char mCombiningClass:8;
};
/;
&genTables("#if !ENABLE_INTL_API", "#endif",
"CharProp1", $type, "nsCharProps1", 11, 5, \&sprintCharProps1, 1, 2, 1);
sub sprintCharProps2_short
{
my $usv = shift;
return sprintf("{%d,%d},",
$verticalOrientation[$usv], $idtype[$usv]);
}
$type = q|
my $type = q|
struct nsCharProps2 {
// Currently only 4 bits are defined here, so 4 more could be added without
// affecting the storage requirements for this struct. Or we could pack two
@ -787,41 +362,7 @@ struct nsCharProps2 {
unsigned char mIdType:2;
};
|;
&genTables("#if ENABLE_INTL_API", "#endif",
"CharProp2", $type, "nsCharProps2", 9, 7, \&sprintCharProps2_short, 16, 1, 1);
sub sprintCharProps2_full
{
my $usv = shift;
return sprintf("{%d,%d,%d,%d,%d,%d,%d,%d,%d,%d},",
$script[$usv], $pairedBracketType[$usv],
$eastAsianWidthFWH[$usv], $category[$usv],
$idtype[$usv], $defaultIgnorable[$usv], $bidicategory[$usv],
$verticalOrientation[$usv], $lineBreak[$usv],
$numericvalue[$usv]);
}
$type = q|
// This struct currently requires 5 bytes. We try to ensure that whole-byte
// fields will not straddle byte boundaries, to optimize access to them.
struct nsCharProps2 {
unsigned char mScriptCode:8;
// -- byte boundary --
unsigned char mPairedBracketType:2;
unsigned char mEastAsianWidthFWH:1;
unsigned char mCategory:5;
// -- byte boundary --
unsigned char mIdType:2;
unsigned char mDefaultIgnorable:1;
unsigned char mBidiCategory:5;
// -- byte boundary --
unsigned char mVertOrient:2;
unsigned char mLineBreak:6;
// -- byte boundary --
signed char mNumericValue; // only 5 bits are actually needed here
};
|;
&genTables("#if !ENABLE_INTL_API", "#endif",
"CharProp2", $type, "nsCharProps2", 12, 4, \&sprintCharProps2_full, 16, 5, 1);
&genTables("CharProp2", $type, "nsCharProps2", 9, 7, \&sprintCharProps2_short, 16, 1, 1);
print HEADER "#pragma pack()\n\n";
@ -837,50 +378,32 @@ sub sprintHanVariants
return sprintf("0x%02x,", $val);
}
## Han Variant data currently unused but may be needed in future, see bug 857481
## &genTables("", "", "HanVariant", "", "uint8_t", 9, 7, \&sprintHanVariants, 2, 1, 4);
## &genTables("HanVariant", "", "uint8_t", 9, 7, \&sprintHanVariants, 2, 1, 4);
sub sprintFullWidth
{
my $usv = shift;
return sprintf("0x%04x,", $fullWidth[$usv]);
}
&genTables("", "", "FullWidth", "", "uint16_t", 10, 6, \&sprintFullWidth, 0, 2, 1);
&genTables("FullWidth", "", "uint16_t", 10, 6, \&sprintFullWidth, 0, 2, 1);
sub sprintFullWidthInverse
{
my $usv = shift;
return sprintf("0x%04x,", $fullWidthInverse[$usv]);
}
&genTables("", "", "FullWidthInverse", "", "uint16_t", 10, 6, \&sprintFullWidthInverse, 0, 2, 1);
sub sprintCasemap
{
my $usv = shift;
return sprintf("0x%08x,", $casemap[$usv]);
}
&genTables("#if !ENABLE_INTL_API", "#endif",
"CaseMap", "", "uint32_t", 11, 5, \&sprintCasemap, 1, 4, 1);
&genTables("FullWidthInverse", "", "uint16_t", 10, 6, \&sprintFullWidthInverse, 0, 2, 1);
print STDERR "Total data = $totalData\n";
printf DATA_TABLES "const uint32_t kTitleToUpper = 0x%08x;\n", $kTitleToUpper;
printf DATA_TABLES "const uint32_t kUpperToLower = 0x%08x;\n", $kUpperToLower;
printf DATA_TABLES "const uint32_t kLowerToTitle = 0x%08x;\n", $kLowerToTitle;
printf DATA_TABLES "const uint32_t kLowerToUpper = 0x%08x;\n", $kLowerToUpper;
printf DATA_TABLES "const uint32_t kCaseMapCharMask = 0x%08x;\n\n", $kCaseMapCharMask;
sub genTables
{
my ($guardBegin, $guardEnd,
$prefix, $typedef, $type, $indexBits, $charBits, $func, $maxPlane, $bytesPerEntry, $charsPerEntry) = @_;
my ($prefix, $typedef, $type, $indexBits, $charBits, $func, $maxPlane, $bytesPerEntry, $charsPerEntry) = @_;
if ($typedef ne '') {
print HEADER "$guardBegin\n";
print HEADER "$typedef\n";
print HEADER "$guardEnd\n\n";
}
print DATA_TABLES "\n$guardBegin\n";
print DATA_TABLES "#define k${prefix}MaxPlane $maxPlane\n";
print DATA_TABLES "#define k${prefix}IndexBits $indexBits\n";
print DATA_TABLES "#define k${prefix}CharBits $charBits\n";
@ -949,7 +472,6 @@ sub genTables
print DATA_TABLES $i < $#char ? "},\n" : "}\n";
}
print DATA_TABLES "};\n";
print DATA_TABLES "$guardEnd\n";
my $dataSize = $pmCount * $indexLen * $pmBits/8 +
$chCount * $pageLen * $bytesPerEntry +

Просмотреть файл

@ -13,30 +13,6 @@
#define UNICODE_BMP_LIMIT 0x10000
#define UNICODE_LIMIT 0x110000
#ifndef ENABLE_INTL_API
static const nsCharProps1&
GetCharProps1(uint32_t aCh)
{
if (aCh < UNICODE_BMP_LIMIT) {
return sCharProp1Values[sCharProp1Pages[0][aCh >> kCharProp1CharBits]]
[aCh & ((1 << kCharProp1CharBits) - 1)];
}
if (aCh < (kCharProp1MaxPlane + 1) * 0x10000) {
return sCharProp1Values[sCharProp1Pages[sCharProp1Planes[(aCh >> 16) - 1]]
[(aCh & 0xffff) >> kCharProp1CharBits]]
[aCh & ((1 << kCharProp1CharBits) - 1)];
}
// Default values for unassigned
static const nsCharProps1 undefined = {
0, // Index to mirrored char offsets
0, // Hangul Syllable type
0 // Combining class
};
return undefined;
}
#endif
const nsCharProps2&
GetCharProps2(uint32_t aCh)
{
@ -54,21 +30,8 @@ GetCharProps2(uint32_t aCh)
// Default values for unassigned
using namespace mozilla::unicode;
static const nsCharProps2 undefined = {
#if ENABLE_INTL_API
VERTICAL_ORIENTATION_R,
0 // IdentifierType
#else
uint8_t(Script::UNKNOWN),
PAIRED_BRACKET_TYPE_NONE,
0, // EastAsianWidthFWH
HB_UNICODE_GENERAL_CATEGORY_UNASSIGNED,
0, // IdentifierType
0, // DefaultIgnorable
eCharType_LeftToRight,
VERTICAL_ORIENTATION_R,
0, // LineBreak
-1 // Numeric Value
#endif
};
return undefined;
}
@ -135,7 +98,6 @@ const nsUGenCategory sDetailedToGeneralCategory[] = {
/* SPACE_SEPARATOR */ nsUGenCategory::kSeparator
};
#ifdef ENABLE_INTL_API
const hb_unicode_general_category_t sICUtoHBcategory[U_CHAR_CATEGORY_COUNT] = {
HB_UNICODE_GENERAL_CATEGORY_UNASSIGNED, // U_GENERAL_OTHER_TYPES = 0,
HB_UNICODE_GENERAL_CATEGORY_UPPERCASE_LETTER, // U_UPPERCASE_LETTER = 1,
@ -168,142 +130,6 @@ const hb_unicode_general_category_t sICUtoHBcategory[U_CHAR_CATEGORY_COUNT] = {
HB_UNICODE_GENERAL_CATEGORY_INITIAL_PUNCTUATION, // U_INITIAL_PUNCTUATION = 28,
HB_UNICODE_GENERAL_CATEGORY_FINAL_PUNCTUATION, // U_FINAL_PUNCTUATION = 29,
};
#endif
#if !ENABLE_INTL_API
uint8_t GetGeneralCategory(uint32_t aCh) {
return GetCharProps2(aCh).mCategory;
}
nsCharType GetBidiCat(uint32_t aCh) {
return nsCharType(GetCharProps2(aCh).mBidiCategory);
}
int8_t GetNumericValue(uint32_t aCh) {
return GetCharProps2(aCh).mNumericValue;
}
uint32_t
GetMirroredChar(uint32_t aCh)
{
return aCh + sMirrorOffsets[GetCharProps1(aCh).mMirrorOffsetIndex];
}
bool
HasMirroredChar(uint32_t aCh)
{
return GetCharProps1(aCh).mMirrorOffsetIndex != 0;
}
uint8_t
GetCombiningClass(uint32_t aCh)
{
return GetCharProps1(aCh).mCombiningClass;
}
uint8_t
GetLineBreakClass(uint32_t aCh)
{
return GetCharProps2(aCh).mLineBreak;
}
Script
GetScriptCode(uint32_t aCh)
{
return Script(GetCharProps2(aCh).mScriptCode);
}
uint32_t
GetScriptTagForCode(Script aScriptCode)
{
// this will safely return 0 for negative script codes, too :)
if (static_cast<uint32_t>(aScriptCode) > ArrayLength(sScriptCodeToTag)) {
return 0;
}
return sScriptCodeToTag[static_cast<uint32_t>(aScriptCode)];
}
PairedBracketType GetPairedBracketType(uint32_t aCh)
{
return PairedBracketType(GetCharProps2(aCh).mPairedBracketType);
}
uint32_t GetPairedBracket(uint32_t aCh)
{
return GetPairedBracketType(aCh) != PAIRED_BRACKET_TYPE_NONE
? GetMirroredChar(aCh) : aCh;
}
static inline uint32_t
GetCaseMapValue(uint32_t aCh)
{
if (aCh < UNICODE_BMP_LIMIT) {
return sCaseMapValues[sCaseMapPages[0][aCh >> kCaseMapCharBits]]
[aCh & ((1 << kCaseMapCharBits) - 1)];
}
if (aCh < (kCaseMapMaxPlane + 1) * 0x10000) {
return sCaseMapValues[sCaseMapPages[sCaseMapPlanes[(aCh >> 16) - 1]]
[(aCh & 0xffff) >> kCaseMapCharBits]]
[aCh & ((1 << kCaseMapCharBits) - 1)];
}
return 0;
}
uint32_t
GetUppercase(uint32_t aCh)
{
uint32_t mapValue = GetCaseMapValue(aCh);
if (mapValue & (kLowerToUpper | kTitleToUpper)) {
return aCh ^ (mapValue & kCaseMapCharMask);
}
if (mapValue & kLowerToTitle) {
return GetUppercase(aCh ^ (mapValue & kCaseMapCharMask));
}
return aCh;
}
uint32_t
GetLowercase(uint32_t aCh)
{
uint32_t mapValue = GetCaseMapValue(aCh);
if (mapValue & kUpperToLower) {
return aCh ^ (mapValue & kCaseMapCharMask);
}
if (mapValue & kTitleToUpper) {
return GetLowercase(aCh ^ (mapValue & kCaseMapCharMask));
}
return aCh;
}
uint32_t
GetTitlecaseForLower(uint32_t aCh)
{
uint32_t mapValue = GetCaseMapValue(aCh);
if (mapValue & (kLowerToTitle | kLowerToUpper)) {
return aCh ^ (mapValue & kCaseMapCharMask);
}
return aCh;
}
uint32_t
GetTitlecaseForAll(uint32_t aCh)
{
uint32_t mapValue = GetCaseMapValue(aCh);
if (mapValue & (kLowerToTitle | kLowerToUpper)) {
return aCh ^ (mapValue & kCaseMapCharMask);
}
if (mapValue & kUpperToLower) {
return GetTitlecaseForLower(aCh ^ (mapValue & kCaseMapCharMask));
}
return aCh;
}
bool IsEastAsianWidthFWH(uint32_t aCh)
{
return GetCharProps2(aCh).mEastAsianWidthFWH;
}
#endif
#define DEFINE_BMP_1PLANE_MAPPING_GET_FUNC(prefix_) \
uint32_t Get##prefix_(uint32_t aCh) \
@ -332,31 +158,18 @@ IsClusterExtender(uint32_t aCh, uint8_t aCategory)
}
enum HSType {
#if ENABLE_INTL_API
HST_NONE = U_HST_NOT_APPLICABLE,
HST_L = U_HST_LEADING_JAMO,
HST_V = U_HST_VOWEL_JAMO,
HST_T = U_HST_TRAILING_JAMO,
HST_LV = U_HST_LV_SYLLABLE,
HST_LVT = U_HST_LVT_SYLLABLE
#else
HST_NONE = 0x00,
HST_L = 0x01,
HST_V = 0x02,
HST_T = 0x04,
HST_LV = 0x03,
HST_LVT = 0x07
#endif
};
static HSType
GetHangulSyllableType(uint32_t aCh)
{
#if ENABLE_INTL_API
return HSType(u_getIntPropertyValue(aCh, UCHAR_HANGUL_SYLLABLE_TYPE));
#else
return HSType(GetCharProps1(aCh).mHangulType);
#endif
}
void

Просмотреть файл

@ -12,10 +12,8 @@
#include "nsUnicodeScriptCodes.h"
#include "harfbuzz/hb.h"
#if ENABLE_INTL_API
#include "unicode/uchar.h"
#include "unicode/uscript.h"
#endif
const nsCharProps2& GetCharProps2(uint32_t aCh);
@ -48,8 +46,6 @@ enum IdentifierType {
IDTYPE_ALLOWED = 1,
};
#if ENABLE_INTL_API // ICU is available, so simply forward to its API
extern const hb_unicode_general_category_t sICUtoHBcategory[];
inline uint32_t
@ -176,63 +172,6 @@ IsDefaultIgnorable(uint32_t aCh)
return u_hasBinaryProperty(aCh, UCHAR_DEFAULT_IGNORABLE_CODE_POINT);
}
#else // not ENABLE_INTL_API
// Return whether the char has a mirrored-pair counterpart.
uint32_t GetMirroredChar(uint32_t aCh);
bool HasMirroredChar(uint32_t aChr);
uint8_t GetCombiningClass(uint32_t aCh);
// returns the detailed General Category in terms of HB_UNICODE_* values
uint8_t GetGeneralCategory(uint32_t aCh);
nsCharType GetBidiCat(uint32_t aCh);
uint8_t GetLineBreakClass(uint32_t aCh);
Script GetScriptCode(uint32_t aCh);
// We don't support ScriptExtensions.txt data when building without ICU.
// The most important cases will still be handled in gfxScriptItemizer
// by checking IsClusterExtender to avoid breaking script runs within
// a cluster.
inline bool
HasScript(uint32_t aCh, Script aScript)
{
return false;
}
uint32_t GetScriptTagForCode(Script aScriptCode);
PairedBracketType GetPairedBracketType(uint32_t aCh);
uint32_t GetPairedBracket(uint32_t aCh);
/**
* Return the numeric value of the character. The value returned is the value
* of the Numeric_Value in field 7 of the UCD, or -1 if field 7 is empty.
* To restrict to decimal digits, the caller should also check whether
* GetGeneralCategory returns HB_UNICODE_GENERAL_CATEGORY_DECIMAL_NUMBER
*/
int8_t GetNumericValue(uint32_t aCh);
uint32_t GetUppercase(uint32_t aCh);
uint32_t GetLowercase(uint32_t aCh);
uint32_t GetTitlecaseForLower(uint32_t aCh); // maps LC to titlecase, UC unchanged
uint32_t GetTitlecaseForAll(uint32_t aCh); // maps both UC and LC to titlecase
// Return whether the char has EastAsianWidth class F or W or H.
bool IsEastAsianWidthFWH(uint32_t aCh);
// Return whether the char is default-ignorable.
inline bool IsDefaultIgnorable(uint32_t aCh)
{
return GetCharProps2(aCh).mDefaultIgnorable;
}
#endif // !ENABLE_INTL_API
// returns the simplified Gen Category as defined in nsUGenCategory
inline nsUGenCategory GetGenCategory(uint32_t aCh) {
return sDetailedToGeneralCategory[GetGeneralCategory(aCh)];

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

Просмотреть файл

@ -11,7 +11,7 @@
*/
/*
* Created on Wed Jun 28 17:08:23 2017 from UCD data files with version info:
* Created on Thu Sep 21 20:35:51 2017 from UCD data files with version info:
*
# Unicode Character Database
@ -29,27 +29,6 @@
This directory contains the final data files
for the Unicode Character Database, for Version 10.0.0 of the Unicode Standard.
# Scripts-10.0.0.txt
# Date: 2017-03-11, 06:40:37 GMT
# BidiMirroring-10.0.0.txt
# Date: 2017-04-12, 17:30:00 GMT [KW, LI]
# BidiBrackets-10.0.0.txt
# Date: 2017-04-12, 17:30:00 GMT [AG, LI, KW]
# HangulSyllableType-10.0.0.txt
# Date: 2017-02-14, 04:26:11 GMT
# LineBreak-10.0.0.txt
# Date: 2017-03-08, 02:00:00 GMT [KW, LI]
# EastAsianWidth-10.0.0.txt
# Date: 2017-03-08, 02:00:00 GMT [KW, LI]
# DerivedCoreProperties-10.0.0.txt
# Date: 2017-03-19, 00:05:15 GMT
# IdentifierStatus.txt
# Date: 2017-04-08, 16:13:41 GMT
@ -69,17 +48,6 @@ for the Unicode Character Database, for Version 10.0.0 of the Unicode Standard.
#pragma pack(1)
#if !ENABLE_INTL_API
struct nsCharProps1 {
unsigned char mMirrorOffsetIndex:5;
unsigned char mHangulType:3;
unsigned char mCombiningClass:8;
};
#endif
#if ENABLE_INTL_API
struct nsCharProps2 {
// Currently only 4 bits are defined here, so 4 more could be added without
@ -89,31 +57,6 @@ struct nsCharProps2 {
unsigned char mIdType:2;
};
#endif
#if !ENABLE_INTL_API
// This struct currently requires 5 bytes. We try to ensure that whole-byte
// fields will not straddle byte boundaries, to optimize access to them.
struct nsCharProps2 {
unsigned char mScriptCode:8;
// -- byte boundary --
unsigned char mPairedBracketType:2;
unsigned char mEastAsianWidthFWH:1;
unsigned char mCategory:5;
// -- byte boundary --
unsigned char mIdType:2;
unsigned char mDefaultIgnorable:1;
unsigned char mBidiCategory:5;
// -- byte boundary --
unsigned char mVertOrient:2;
unsigned char mLineBreak:6;
// -- byte boundary --
signed char mNumericValue; // only 5 bits are actually needed here
};
#endif
#pragma pack()
namespace mozilla {

Просмотреть файл

@ -3,6 +3,7 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
include('/media/webrtc/webrtc.mozbuild')
EXPORTS += [
'nsIIPCBackgroundChildCreateCallback.h',
@ -51,7 +52,6 @@ if CONFIG['FUZZING'] == '1':
SOURCES += ['Faulty.cpp']
if CONFIG['OS_ARCH'] == 'WINNT':
DEFINES['WEBRTC_WIN'] = True
EXPORTS.mozilla.ipc += [
'Transport_win.h',
]
@ -61,7 +61,6 @@ if CONFIG['OS_ARCH'] == 'WINNT':
'WindowsMessageLoop.cpp',
]
else:
DEFINES['WEBRTC_POSIX'] = True
EXPORTS.mozilla.ipc += [
'Transport_posix.h',
]

Просмотреть файл

@ -150,6 +150,8 @@ class Assembler : public AssemblerShared
static void ToggleToCmp(CodeLocationLabel) { MOZ_CRASH(); }
static void ToggleCall(CodeLocationLabel, bool) { MOZ_CRASH(); }
static void Bind(uint8_t*, CodeOffset, CodeOffset) { MOZ_CRASH(); }
static uintptr_t GetPointer(uint8_t*) { MOZ_CRASH(); }
static bool HasRoundInstruction(RoundingMode) { return false; }
@ -187,7 +189,9 @@ class MacroAssemblerNone : public Assembler
size_t numCodeLabels() const { MOZ_CRASH(); }
CodeLabel codeLabel(size_t) { MOZ_CRASH(); }
bool reserve(size_t size) { MOZ_CRASH(); }
bool appendRawCode(const uint8_t* code, size_t numBytes) { MOZ_CRASH(); }
bool swapBuffer(wasm::Bytes& bytes) { MOZ_CRASH(); }
void trace(JSTracer*) { MOZ_CRASH(); }
static void TraceJumpRelocations(JSTracer*, JitCode*, CompactBufferReader&) { MOZ_CRASH(); }

Просмотреть файл

@ -208,15 +208,15 @@ ServoRestyleState::ProcessMaybeNestedWrapperRestyle(nsIFrame* aParent,
(parent->StyleContext()->IsInheritingAnonBox() &&
parent->GetContent() == aParent->GetContent()));
// Now "this" is a ServoRestyleState for aParent, so if parent is not a prev
// Now "this" is a ServoRestyleState for aParent, so if parent is not a next
// continuation (possibly across ib splits) of aParent we need a new
// ServoRestyleState for the kid.
Maybe<ServoRestyleState> parentRestyleState;
nsIFrame* parentForRestyle = aParent;
if (nsLayoutUtils::FirstContinuationOrIBSplitSibling(parent) != aParent) {
parentRestyleState.emplace(*parent, *this, nsChangeHint_Empty,
nsIFrame* parentForRestyle =
nsLayoutUtils::FirstContinuationOrIBSplitSibling(parent);
if (parentForRestyle != aParent) {
parentRestyleState.emplace(*parentForRestyle, *this, nsChangeHint_Empty,
Type::InFlow);
parentForRestyle = parent;
}
ServoRestyleState& curRestyleState =
parentRestyleState ? *parentRestyleState : *this;

Просмотреть файл

@ -0,0 +1,11 @@
<style>
html { -moz-column-width:0 }
</style>
<script>
document.documentElement.appendChild(document.createElement("option"))
document.documentElement.appendChild(document.createElement("th"))
document.styleSheets[0].insertRule("c{", 0)
document.documentElement.getBoundingClientRect()
document.styleSheets[0].deleteRule(0)
</script>
<body></body>

Просмотреть файл

@ -503,4 +503,5 @@ load 1397398-3.html
load 1398500.html
load 1400438-1.html
load 1400599-1.html
load 1401739.html
load 1401840.html

Просмотреть файл

@ -45,8 +45,6 @@ span { color:blue; }
<span style="color:green">R</span>
<div></div>
<b style="color:green">V</b>
<b style="color:green">W</b>
<b style="color:green">X</b>
<!-- <b style="color:green">Y</b> -->
</body>
</html>

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше