merge mozilla-inbound to mozilla-central. r=merge a=merge
merge mozilla-inbound to mozilla-central. r=merge a=merge
MozReview-Commit-ID: 517PGVX0wPB
--- a/browser/base/content/test/performance/browser_windowopen_reflows.js
+++ b/browser/base/content/test/performance/browser_windowopen_reflows.js
@@ -90,18 +90,17 @@ if (Services.appinfo.OS == "WINNT" || Se
"init@chrome://browser/content/browser-tabsintitlebar.js",
"handleEvent@chrome://browser/content/tabbrowser.xml",
],
times: 4, // This number should only ever go down - never up.
},
);
}
-// Windows Vista, 7 or 8
-if (navigator.userAgent.indexOf("Windows NT 6") != -1) {
+if (Services.appinfo.OS == "WINNT" && screen.width <= 1280) {
EXPECTED_REFLOWS.push(
{
stack: [
"handleEvent@chrome://browser/content/tabbrowser.xml",
],
},
);
}
--- a/browser/extensions/pdfjs/README.mozilla
+++ b/browser/extensions/pdfjs/README.mozilla
@@ -1,5 +1,5 @@
This is the PDF.js project output, https://github.com/mozilla/pdf.js
-Current extension version is: 1.9.583
+Current extension version is: 1.9.597
-Taken from upstream commit: d7b37ae7
+Taken from upstream commit: f3987bba
--- a/browser/extensions/pdfjs/content/build/pdf.js
+++ b/browser/extensions/pdfjs/content/build/pdf.js
@@ -3304,18 +3304,18 @@ var _UnsupportedManager = function Unsup
for (var i = 0, ii = listeners.length; i < ii; i++) {
listeners[i](featureId);
}
}
};
}();
var version, build;
{
- exports.version = version = '1.9.583';
- exports.build = build = 'd7b37ae7';
+ exports.version = version = '1.9.597';
+ exports.build = build = 'f3987bba';
}
exports.getDocument = getDocument;
exports.LoopbackPort = LoopbackPort;
exports.PDFDataRangeTransport = PDFDataRangeTransport;
exports.PDFWorker = PDFWorker;
exports.PDFDocumentProxy = PDFDocumentProxy;
exports.PDFPageProxy = PDFPageProxy;
exports.setPDFNetworkStreamClass = setPDFNetworkStreamClass;
@@ -3819,16 +3819,20 @@ class AnnotationElementFactory {
case _util.AnnotationType.POPUP:
return new PopupAnnotationElement(parameters);
case _util.AnnotationType.LINE:
return new LineAnnotationElement(parameters);
case _util.AnnotationType.SQUARE:
return new SquareAnnotationElement(parameters);
case _util.AnnotationType.CIRCLE:
return new CircleAnnotationElement(parameters);
+ case _util.AnnotationType.POLYLINE:
+ return new PolylineAnnotationElement(parameters);
+ case _util.AnnotationType.POLYGON:
+ return new PolygonAnnotationElement(parameters);
case _util.AnnotationType.HIGHLIGHT:
return new HighlightAnnotationElement(parameters);
case _util.AnnotationType.UNDERLINE:
return new UnderlineAnnotationElement(parameters);
case _util.AnnotationType.SQUIGGLY:
return new SquigglyAnnotationElement(parameters);
case _util.AnnotationType.STRIKEOUT:
return new StrikeOutAnnotationElement(parameters);
@@ -4124,17 +4128,17 @@ class ChoiceWidgetAnnotationElement exte
}
}
class PopupAnnotationElement extends AnnotationElement {
constructor(parameters) {
let isRenderable = !!(parameters.data.title || parameters.data.contents);
super(parameters, isRenderable);
}
render() {
- const IGNORE_TYPES = ['Line', 'Square', 'Circle'];
+ const IGNORE_TYPES = ['Line', 'Square', 'Circle', 'PolyLine', 'Polygon'];
this.container.className = 'popupAnnotation';
if (IGNORE_TYPES.indexOf(this.data.parentType) >= 0) {
return this.container;
}
let selector = '[data-annotation-id="' + this.data.parentId + '"]';
let parentElement = this.layer.querySelector(selector);
if (!parentElement) {
return this.container;
@@ -4300,16 +4304,56 @@ class CircleAnnotationElement extends An
circle.setAttribute('stroke', 'transparent');
circle.setAttribute('fill', 'none');
svg.appendChild(circle);
this.container.append(svg);
this._createPopup(this.container, circle, data);
return this.container;
}
}
+class PolylineAnnotationElement extends AnnotationElement {
+ constructor(parameters) {
+ let isRenderable = !!(parameters.data.hasPopup || parameters.data.title || parameters.data.contents);
+ super(parameters, isRenderable, true);
+ this.containerClassName = 'polylineAnnotation';
+ this.svgElementName = 'svg:polyline';
+ }
+ render() {
+ this.container.className = this.containerClassName;
+ let data = this.data;
+ let width = data.rect[2] - data.rect[0];
+ let height = data.rect[3] - data.rect[1];
+ let svg = this.svgFactory.create(width, height);
+ let vertices = data.vertices;
+ let points = [];
+ for (let i = 0, ii = vertices.length; i < ii; i++) {
+ let x = vertices[i].x - data.rect[0];
+ let y = data.rect[3] - vertices[i].y;
+ points.push(x + ',' + y);
+ }
+ points = points.join(' ');
+ let borderWidth = data.borderStyle.width;
+ let polyline = this.svgFactory.createElement(this.svgElementName);
+ polyline.setAttribute('points', points);
+ polyline.setAttribute('stroke-width', borderWidth);
+ polyline.setAttribute('stroke', 'transparent');
+ polyline.setAttribute('fill', 'none');
+ svg.appendChild(polyline);
+ this.container.append(svg);
+ this._createPopup(this.container, polyline, data);
+ return this.container;
+ }
+}
+class PolygonAnnotationElement extends PolylineAnnotationElement {
+ constructor(parameters) {
+ super(parameters);
+ this.containerClassName = 'polygonAnnotation';
+ this.svgElementName = 'svg:polygon';
+ }
+}
class HighlightAnnotationElement extends AnnotationElement {
constructor(parameters) {
let isRenderable = !!(parameters.data.hasPopup || parameters.data.title || parameters.data.contents);
super(parameters, isRenderable, true);
}
render() {
this.container.className = 'highlightAnnotation';
if (!this.data.hasPopup) {
@@ -5000,18 +5044,18 @@ exports.SVGGraphics = SVGGraphics;
/***/ }),
/* 9 */
/***/ (function(module, exports, __w_pdfjs_require__) {
"use strict";
-var pdfjsVersion = '1.9.583';
-var pdfjsBuild = 'd7b37ae7';
+var pdfjsVersion = '1.9.597';
+var pdfjsBuild = 'f3987bba';
var pdfjsSharedUtil = __w_pdfjs_require__(0);
var pdfjsDisplayGlobal = __w_pdfjs_require__(13);
var pdfjsDisplayAPI = __w_pdfjs_require__(3);
var pdfjsDisplayTextLayer = __w_pdfjs_require__(7);
var pdfjsDisplayAnnotationLayer = __w_pdfjs_require__(6);
var pdfjsDisplayDOMUtils = __w_pdfjs_require__(1);
var pdfjsDisplaySVG = __w_pdfjs_require__(8);
;
@@ -8127,18 +8171,18 @@ var _svg = __w_pdfjs_require__(8);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
var isWorker = typeof window === 'undefined';
if (!_global_scope2.default.PDFJS) {
_global_scope2.default.PDFJS = {};
}
var PDFJS = _global_scope2.default.PDFJS;
{
- PDFJS.version = '1.9.583';
- PDFJS.build = 'd7b37ae7';
+ PDFJS.version = '1.9.597';
+ PDFJS.build = 'f3987bba';
}
PDFJS.pdfBug = false;
if (PDFJS.verbosity !== undefined) {
(0, _util.setVerbosityLevel)(PDFJS.verbosity);
}
delete PDFJS.verbosity;
Object.defineProperty(PDFJS, 'verbosity', {
get() {
--- a/browser/extensions/pdfjs/content/build/pdf.worker.js
+++ b/browser/extensions/pdfjs/content/build/pdf.worker.js
@@ -3515,20 +3515,17 @@ var ColorSpace = function ColorSpaceClos
destPos += alpha01;
}
}
}
},
usesZeroToOneRange: true
};
ColorSpace.parse = function ColorSpace_parse(cs, xref, res) {
- var IR = ColorSpace.parseToIR(cs, xref, res);
- if (IR instanceof AlternateCS) {
- return IR;
- }
+ let IR = ColorSpace.parseToIR(cs, xref, res);
return ColorSpace.fromIR(IR);
};
ColorSpace.fromIR = function ColorSpace_fromIR(IR) {
var name = Array.isArray(IR) ? IR[0] : IR;
var whitePoint, blackPoint, gamma;
switch (name) {
case 'DeviceGrayCS':
return this.singletons.gray;
@@ -23725,18 +23722,18 @@ exports.getUnicodeForGlyph = getUnicodeF
/***/ }),
/* 17 */
/***/ (function(module, exports, __w_pdfjs_require__) {
"use strict";
-var pdfjsVersion = '1.9.583';
-var pdfjsBuild = 'd7b37ae7';
+var pdfjsVersion = '1.9.597';
+var pdfjsBuild = 'f3987bba';
var pdfjsCoreWorker = __w_pdfjs_require__(18);
exports.WorkerMessageHandler = pdfjsCoreWorker.WorkerMessageHandler;
/***/ }),
/* 18 */
/***/ (function(module, exports, __w_pdfjs_require__) {
"use strict";
@@ -28623,18 +28620,18 @@ var Jbig2Image = function Jbig2ImageClos
var rdw = decodeInteger(contextCache, 'IARDW', decoder);
var rdh = decodeInteger(contextCache, 'IARDH', decoder);
var rdx = decodeInteger(contextCache, 'IARDX', decoder);
var rdy = decodeInteger(contextCache, 'IARDY', decoder);
symbolWidth += rdw;
symbolHeight += rdh;
symbolBitmap = decodeRefinement(symbolWidth, symbolHeight, refinementTemplateIndex, symbolBitmap, (rdw >> 1) + rdx, (rdh >> 1) + rdy, false, refinementAt, decodingContext);
}
- var offsetT = t - (referenceCorner & 1 ? 0 : symbolHeight);
- var offsetS = currentS - (referenceCorner & 2 ? symbolWidth : 0);
+ var offsetT = t - (referenceCorner & 1 ? 0 : symbolHeight - 1);
+ var offsetS = currentS - (referenceCorner & 2 ? symbolWidth - 1 : 0);
var s2, t2, symbolRow;
if (transposed) {
for (s2 = 0; s2 < symbolHeight; s2++) {
row = bitmap[offsetS + s2];
if (!row) {
continue;
}
symbolRow = symbolBitmap[s2];
@@ -39542,16 +39539,20 @@ class AnnotationFactory {
case 'Popup':
return new PopupAnnotation(parameters);
case 'Line':
return new LineAnnotation(parameters);
case 'Square':
return new SquareAnnotation(parameters);
case 'Circle':
return new CircleAnnotation(parameters);
+ case 'PolyLine':
+ return new PolylineAnnotation(parameters);
+ case 'Polygon':
+ return new PolygonAnnotation(parameters);
case 'Highlight':
return new HighlightAnnotation(parameters);
case 'Underline':
return new UnderlineAnnotation(parameters);
case 'Squiggly':
return new SquigglyAnnotation(parameters);
case 'StrikeOut':
return new StrikeOutAnnotation(parameters);
@@ -40050,16 +40051,38 @@ class SquareAnnotation extends Annotatio
}
class CircleAnnotation extends Annotation {
constructor(parameters) {
super(parameters);
this.data.annotationType = _util.AnnotationType.CIRCLE;
this._preparePopup(parameters.dict);
}
}
+class PolylineAnnotation extends Annotation {
+ constructor(parameters) {
+ super(parameters);
+ this.data.annotationType = _util.AnnotationType.POLYLINE;
+ let dict = parameters.dict;
+ let rawVertices = dict.getArray('Vertices');
+ this.data.vertices = [];
+ for (let i = 0, ii = rawVertices.length; i < ii; i += 2) {
+ this.data.vertices.push({
+ x: rawVertices[i],
+ y: rawVertices[i + 1]
+ });
+ }
+ this._preparePopup(dict);
+ }
+}
+class PolygonAnnotation extends PolylineAnnotation {
+ constructor(parameters) {
+ super(parameters);
+ this.data.annotationType = _util.AnnotationType.POLYGON;
+ }
+}
class HighlightAnnotation extends Annotation {
constructor(parameters) {
super(parameters);
this.data.annotationType = _util.AnnotationType.HIGHLIGHT;
this._preparePopup(parameters.dict);
}
}
class UnderlineAnnotation extends Annotation {
--- a/browser/extensions/pdfjs/content/web/viewer.css
+++ b/browser/extensions/pdfjs/content/web/viewer.css
@@ -244,16 +244,18 @@
.annotationLayer .highlightAnnotation,
.annotationLayer .underlineAnnotation,
.annotationLayer .squigglyAnnotation,
.annotationLayer .strikeoutAnnotation,
.annotationLayer .lineAnnotation svg line,
.annotationLayer .squareAnnotation svg rect,
.annotationLayer .circleAnnotation svg ellipse,
+.annotationLayer .polylineAnnotation svg polyline,
+.annotationLayer .polygonAnnotation svg polygon,
.annotationLayer .stampAnnotation,
.annotationLayer .fileAttachmentAnnotation {
cursor: pointer;
}
.pdfViewer .canvasWrapper {
overflow: hidden;
}
--- a/browser/extensions/pdfjs/content/web/viewer.js
+++ b/browser/extensions/pdfjs/content/web/viewer.js
@@ -83,29 +83,35 @@
/***/ (function(module, exports, __webpack_require__) {
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
-exports.waitOnEventOrTimeout = exports.WaitOnType = exports.localized = exports.animationStarted = exports.normalizeWheelEventDelta = exports.binarySearchFirstItem = exports.watchScroll = exports.scrollIntoView = exports.getOutputScale = exports.approximateFraction = exports.roundToDivide = exports.getVisibleElements = exports.parseQueryString = exports.noContextMenuHandler = exports.getPDFFileNameFromURL = exports.ProgressBar = exports.EventBus = exports.NullL10n = exports.mozL10n = exports.RendererType = exports.cloneObj = exports.isValidRotation = exports.VERTICAL_PADDING = exports.SCROLLBAR_PADDING = exports.MAX_AUTO_SCALE = exports.UNKNOWN_SCALE = exports.MAX_SCALE = exports.MIN_SCALE = exports.DEFAULT_SCALE = exports.DEFAULT_SCALE_VALUE = exports.CSS_UNITS = undefined;
+exports.waitOnEventOrTimeout = exports.WaitOnType = exports.localized = exports.animationStarted = exports.normalizeWheelEventDelta = exports.binarySearchFirstItem = exports.watchScroll = exports.scrollIntoView = exports.getOutputScale = exports.approximateFraction = exports.roundToDivide = exports.getVisibleElements = exports.parseQueryString = exports.noContextMenuHandler = exports.getPDFFileNameFromURL = exports.ProgressBar = exports.EventBus = exports.NullL10n = exports.mozL10n = exports.RendererType = exports.PresentationModeState = exports.cloneObj = exports.isValidRotation = exports.VERTICAL_PADDING = exports.SCROLLBAR_PADDING = exports.MAX_AUTO_SCALE = exports.UNKNOWN_SCALE = exports.MAX_SCALE = exports.MIN_SCALE = exports.DEFAULT_SCALE = exports.DEFAULT_SCALE_VALUE = exports.CSS_UNITS = undefined;
var _pdfjsLib = __webpack_require__(1);
const CSS_UNITS = 96.0 / 72.0;
const DEFAULT_SCALE_VALUE = 'auto';
const DEFAULT_SCALE = 1.0;
const MIN_SCALE = 0.25;
const MAX_SCALE = 10.0;
const UNKNOWN_SCALE = 0;
const MAX_AUTO_SCALE = 1.25;
const SCROLLBAR_PADDING = 40;
const VERTICAL_PADDING = 5;
+const PresentationModeState = {
+ UNKNOWN: 0,
+ NORMAL: 1,
+ CHANGING: 2,
+ FULLSCREEN: 3
+};
const RendererType = {
CANVAS: 'canvas',
SVG: 'svg'
};
function formatL10nValue(text, args) {
if (!args) {
return text;
}
@@ -513,16 +519,17 @@ exports.DEFAULT_SCALE = DEFAULT_SCALE;
exports.MIN_SCALE = MIN_SCALE;
exports.MAX_SCALE = MAX_SCALE;
exports.UNKNOWN_SCALE = UNKNOWN_SCALE;
exports.MAX_AUTO_SCALE = MAX_AUTO_SCALE;
exports.SCROLLBAR_PADDING = SCROLLBAR_PADDING;
exports.VERTICAL_PADDING = VERTICAL_PADDING;
exports.isValidRotation = isValidRotation;
exports.cloneObj = cloneObj;
+exports.PresentationModeState = PresentationModeState;
exports.RendererType = RendererType;
exports.mozL10n = mozL10n;
exports.NullL10n = NullL10n;
exports.EventBus = EventBus;
exports.ProgressBar = ProgressBar;
exports.getPDFFileNameFromURL = getPDFFileNameFromURL;
exports.noContextMenuHandler = noContextMenuHandler;
exports.parseQueryString = parseQueryString;
@@ -802,47 +809,47 @@ var _ui_utils = __webpack_require__(0);
var _pdfjsLib = __webpack_require__(1);
var _pdf_cursor_tools = __webpack_require__(6);
var _pdf_rendering_queue = __webpack_require__(3);
var _pdf_sidebar = __webpack_require__(10);
-var _pdf_viewer = __webpack_require__(11);
-
var _dom_events = __webpack_require__(2);
-var _overlay_manager = __webpack_require__(15);
-
-var _password_prompt = __webpack_require__(16);
-
-var _pdf_attachment_viewer = __webpack_require__(17);
-
-var _pdf_document_properties = __webpack_require__(18);
-
-var _pdf_find_bar = __webpack_require__(19);
+var _overlay_manager = __webpack_require__(11);
+
+var _password_prompt = __webpack_require__(12);
+
+var _pdf_attachment_viewer = __webpack_require__(13);
+
+var _pdf_document_properties = __webpack_require__(14);
+
+var _pdf_find_bar = __webpack_require__(15);
var _pdf_find_controller = __webpack_require__(7);
-var _pdf_history = __webpack_require__(20);
+var _pdf_history = __webpack_require__(16);
var _pdf_link_service = __webpack_require__(5);
-var _pdf_outline_viewer = __webpack_require__(21);
-
-var _pdf_presentation_mode = __webpack_require__(22);
-
-var _pdf_thumbnail_viewer = __webpack_require__(23);
-
-var _secondary_toolbar = __webpack_require__(25);
-
-var _toolbar = __webpack_require__(26);
-
-var _view_history = __webpack_require__(27);
+var _pdf_outline_viewer = __webpack_require__(17);
+
+var _pdf_presentation_mode = __webpack_require__(18);
+
+var _pdf_thumbnail_viewer = __webpack_require__(19);
+
+var _pdf_viewer = __webpack_require__(21);
+
+var _secondary_toolbar = __webpack_require__(26);
+
+var _toolbar = __webpack_require__(27);
+
+var _view_history = __webpack_require__(28);
const DEFAULT_SCALE_DELTA = 1.1;
const DISABLE_AUTO_FETCH_LOADING_BAR_TIMEOUT = 5000;
function configure(PDFJS) {
PDFJS.imageResourcesPath = './images/';
PDFJS.workerSrc = '../build/pdf.worker.js';
PDFJS.cMapUrl = '../web/cmaps/';
PDFJS.cMapPacked = true;
@@ -1945,17 +1952,17 @@ function webViewerNamedAction(evt) {
if (!PDFViewerApplication.supportsIntegratedFind) {
PDFViewerApplication.findBar.toggle();
}
break;
}
}
function webViewerPresentationModeChanged(evt) {
let { active, switchInProgress } = evt;
- PDFViewerApplication.pdfViewer.presentationModeState = switchInProgress ? _pdf_viewer.PresentationModeState.CHANGING : active ? _pdf_viewer.PresentationModeState.FULLSCREEN : _pdf_viewer.PresentationModeState.NORMAL;
+ PDFViewerApplication.pdfViewer.presentationModeState = switchInProgress ? _ui_utils.PresentationModeState.CHANGING : active ? _ui_utils.PresentationModeState.FULLSCREEN : _ui_utils.PresentationModeState.NORMAL;
}
function webViewerSidebarViewChanged(evt) {
PDFViewerApplication.pdfRenderingQueue.isThumbnailViewEnabled = PDFViewerApplication.pdfSidebar.isThumbnailViewVisible;
let store = PDFViewerApplication.store;
if (store && PDFViewerApplication.isInitialViewSet) {
store.set('sidebarView', evt.view).catch(function () {});
}
}
@@ -3173,18 +3180,18 @@ exports.PDFFindController = PDFFindContr
let DEFAULT_URL = 'compressed.tracemonkey-pldi-09.pdf';
;
let pdfjsWebApp;
{
pdfjsWebApp = __webpack_require__(4);
}
{
- __webpack_require__(28);
- __webpack_require__(31);
+ __webpack_require__(29);
+ __webpack_require__(32);
}
;
;
;
function getViewerConfiguration() {
return {
appContainer: document.body,
mainContainer: document.getElementById('viewerContainer'),
@@ -3753,44 +3760,2022 @@ exports.PDFSidebar = PDFSidebar;
/***/ (function(module, exports, __webpack_require__) {
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
-exports.PDFViewer = exports.PresentationModeState = undefined;
+class OverlayManager {
+ constructor() {
+ this._overlays = {};
+ this._active = null;
+ this._keyDownBound = this._keyDown.bind(this);
+ }
+ get active() {
+ return this._active;
+ }
+ register(name, element, callerCloseMethod = null, canForceClose = false) {
+ return new Promise(resolve => {
+ let container;
+ if (!name || !element || !(container = element.parentNode)) {
+ throw new Error('Not enough parameters.');
+ } else if (this._overlays[name]) {
+ throw new Error('The overlay is already registered.');
+ }
+ this._overlays[name] = {
+ element,
+ container,
+ callerCloseMethod,
+ canForceClose
+ };
+ resolve();
+ });
+ }
+ unregister(name) {
+ return new Promise(resolve => {
+ if (!this._overlays[name]) {
+ throw new Error('The overlay does not exist.');
+ } else if (this._active === name) {
+ throw new Error('The overlay cannot be removed while it is active.');
+ }
+ delete this._overlays[name];
+ resolve();
+ });
+ }
+ open(name) {
+ return new Promise(resolve => {
+ if (!this._overlays[name]) {
+ throw new Error('The overlay does not exist.');
+ } else if (this._active) {
+ if (this._overlays[name].canForceClose) {
+ this._closeThroughCaller();
+ } else if (this._active === name) {
+ throw new Error('The overlay is already active.');
+ } else {
+ throw new Error('Another overlay is currently active.');
+ }
+ }
+ this._active = name;
+ this._overlays[this._active].element.classList.remove('hidden');
+ this._overlays[this._active].container.classList.remove('hidden');
+ window.addEventListener('keydown', this._keyDownBound);
+ resolve();
+ });
+ }
+ close(name) {
+ return new Promise(resolve => {
+ if (!this._overlays[name]) {
+ throw new Error('The overlay does not exist.');
+ } else if (!this._active) {
+ throw new Error('The overlay is currently not active.');
+ } else if (this._active !== name) {
+ throw new Error('Another overlay is currently active.');
+ }
+ this._overlays[this._active].container.classList.add('hidden');
+ this._overlays[this._active].element.classList.add('hidden');
+ this._active = null;
+ window.removeEventListener('keydown', this._keyDownBound);
+ resolve();
+ });
+ }
+ _keyDown(evt) {
+ if (this._active && evt.keyCode === 27) {
+ this._closeThroughCaller();
+ evt.preventDefault();
+ }
+ }
+ _closeThroughCaller() {
+ if (this._overlays[this._active].callerCloseMethod) {
+ this._overlays[this._active].callerCloseMethod();
+ }
+ if (this._active) {
+ this.close(this._active);
+ }
+ }
+}
+exports.OverlayManager = OverlayManager;
+
+/***/ }),
+/* 12 */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.PasswordPrompt = undefined;
+
+var _ui_utils = __webpack_require__(0);
+
+var _pdfjsLib = __webpack_require__(1);
+
+class PasswordPrompt {
+ constructor(options, overlayManager, l10n = _ui_utils.NullL10n) {
+ this.overlayName = options.overlayName;
+ this.container = options.container;
+ this.label = options.label;
+ this.input = options.input;
+ this.submitButton = options.submitButton;
+ this.cancelButton = options.cancelButton;
+ this.overlayManager = overlayManager;
+ this.l10n = l10n;
+ this.updateCallback = null;
+ this.reason = null;
+ this.submitButton.addEventListener('click', this.verify.bind(this));
+ this.cancelButton.addEventListener('click', this.close.bind(this));
+ this.input.addEventListener('keydown', e => {
+ if (e.keyCode === 13) {
+ this.verify();
+ }
+ });
+ this.overlayManager.register(this.overlayName, this.container, this.close.bind(this), true);
+ }
+ open() {
+ this.overlayManager.open(this.overlayName).then(() => {
+ this.input.focus();
+ let promptString;
+ if (this.reason === _pdfjsLib.PasswordResponses.INCORRECT_PASSWORD) {
+ promptString = this.l10n.get('password_invalid', null, 'Invalid password. Please try again.');
+ } else {
+ promptString = this.l10n.get('password_label', null, 'Enter the password to open this PDF file.');
+ }
+ promptString.then(msg => {
+ this.label.textContent = msg;
+ });
+ });
+ }
+ close() {
+ this.overlayManager.close(this.overlayName).then(() => {
+ this.input.value = '';
+ });
+ }
+ verify() {
+ let password = this.input.value;
+ if (password && password.length > 0) {
+ this.close();
+ return this.updateCallback(password);
+ }
+ }
+ setUpdateCallback(updateCallback, reason) {
+ this.updateCallback = updateCallback;
+ this.reason = reason;
+ }
+}
+exports.PasswordPrompt = PasswordPrompt;
+
+/***/ }),
+/* 13 */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.PDFAttachmentViewer = undefined;
+
+var _pdfjsLib = __webpack_require__(1);
+
+class PDFAttachmentViewer {
+ constructor({ container, eventBus, downloadManager }) {
+ this.container = container;
+ this.eventBus = eventBus;
+ this.downloadManager = downloadManager;
+ this.reset();
+ this.eventBus.on('fileattachmentannotation', this._appendAttachment.bind(this));
+ }
+ reset(keepRenderedCapability = false) {
+ this.attachments = null;
+ this.container.textContent = '';
+ if (!keepRenderedCapability) {
+ this._renderedCapability = (0, _pdfjsLib.createPromiseCapability)();
+ }
+ }
+ _dispatchEvent(attachmentsCount) {
+ this._renderedCapability.resolve();
+ this.eventBus.dispatch('attachmentsloaded', {
+ source: this,
+ attachmentsCount
+ });
+ }
+ _bindPdfLink(button, content, filename) {
+ if (_pdfjsLib.PDFJS.disableCreateObjectURL) {
+ throw new Error('bindPdfLink: ' + 'Unsupported "PDFJS.disableCreateObjectURL" value.');
+ }
+ let blobUrl;
+ button.onclick = function () {
+ if (!blobUrl) {
+ blobUrl = (0, _pdfjsLib.createObjectURL)(content, 'application/pdf');
+ }
+ let viewerUrl;
+ viewerUrl = blobUrl + '?' + encodeURIComponent(filename);
+ window.open(viewerUrl);
+ return false;
+ };
+ }
+ _bindLink(button, content, filename) {
+ button.onclick = () => {
+ this.downloadManager.downloadData(content, filename, '');
+ return false;
+ };
+ }
+ render({ attachments, keepRenderedCapability = false }) {
+ let attachmentsCount = 0;
+ if (this.attachments) {
+ this.reset(keepRenderedCapability === true);
+ }
+ this.attachments = attachments || null;
+ if (!attachments) {
+ this._dispatchEvent(attachmentsCount);
+ return;
+ }
+ let names = Object.keys(attachments).sort(function (a, b) {
+ return a.toLowerCase().localeCompare(b.toLowerCase());
+ });
+ attachmentsCount = names.length;
+ for (let i = 0; i < attachmentsCount; i++) {
+ let item = attachments[names[i]];
+ let filename = (0, _pdfjsLib.removeNullCharacters)((0, _pdfjsLib.getFilenameFromUrl)(item.filename));
+ let div = document.createElement('div');
+ div.className = 'attachmentsItem';
+ let button = document.createElement('button');
+ button.textContent = filename;
+ if (/\.pdf$/i.test(filename) && !_pdfjsLib.PDFJS.disableCreateObjectURL) {
+ this._bindPdfLink(button, item.content, filename);
+ } else {
+ this._bindLink(button, item.content, filename);
+ }
+ div.appendChild(button);
+ this.container.appendChild(div);
+ }
+ this._dispatchEvent(attachmentsCount);
+ }
+ _appendAttachment({ id, filename, content }) {
+ this._renderedCapability.promise.then(() => {
+ let attachments = this.attachments;
+ if (!attachments) {
+ attachments = Object.create(null);
+ } else {
+ for (let name in attachments) {
+ if (id === name) {
+ return;
+ }
+ }
+ }
+ attachments[id] = {
+ filename,
+ content
+ };
+ this.render({
+ attachments,
+ keepRenderedCapability: true
+ });
+ });
+ }
+}
+exports.PDFAttachmentViewer = PDFAttachmentViewer;
+
+/***/ }),
+/* 14 */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.PDFDocumentProperties = undefined;
+
+var _ui_utils = __webpack_require__(0);
+
+var _pdfjsLib = __webpack_require__(1);
+
+const DEFAULT_FIELD_CONTENT = '-';
+class PDFDocumentProperties {
+ constructor({ overlayName, fields, container, closeButton }, overlayManager, l10n = _ui_utils.NullL10n) {
+ this.overlayName = overlayName;
+ this.fields = fields;
+ this.container = container;
+ this.overlayManager = overlayManager;
+ this.l10n = l10n;
+ this._reset();
+ if (closeButton) {
+ closeButton.addEventListener('click', this.close.bind(this));
+ }
+ this.overlayManager.register(this.overlayName, this.container, this.close.bind(this));
+ }
+ open() {
+ let freezeFieldData = data => {
+ Object.defineProperty(this, 'fieldData', {
+ value: Object.freeze(data),
+ writable: false,
+ enumerable: true,
+ configurable: true
+ });
+ };
+ Promise.all([this.overlayManager.open(this.overlayName), this._dataAvailableCapability.promise]).then(() => {
+ if (this.fieldData) {
+ this._updateUI();
+ return;
+ }
+ this.pdfDocument.getMetadata().then(({ info, metadata }) => {
+ return Promise.all([info, metadata, this._parseFileSize(this.maybeFileSize), this._parseDate(info.CreationDate), this._parseDate(info.ModDate)]);
+ }).then(([info, metadata, fileSize, creationDate, modificationDate]) => {
+ freezeFieldData({
+ 'fileName': (0, _ui_utils.getPDFFileNameFromURL)(this.url),
+ 'fileSize': fileSize,
+ 'title': info.Title,
+ 'author': info.Author,
+ 'subject': info.Subject,
+ 'keywords': info.Keywords,
+ 'creationDate': creationDate,
+ 'modificationDate': modificationDate,
+ 'creator': info.Creator,
+ 'producer': info.Producer,
+ 'version': info.PDFFormatVersion,
+ 'pageCount': this.pdfDocument.numPages
+ });
+ this._updateUI();
+ return this.pdfDocument.getDownloadInfo();
+ }).then(({ length }) => {
+ return this._parseFileSize(length);
+ }).then(fileSize => {
+ let data = (0, _ui_utils.cloneObj)(this.fieldData);
+ data['fileSize'] = fileSize;
+ freezeFieldData(data);
+ this._updateUI();
+ });
+ });
+ }
+ close() {
+ this.overlayManager.close(this.overlayName);
+ }
+ setDocument(pdfDocument, url) {
+ if (this.pdfDocument) {
+ this._reset();
+ this._updateUI(true);
+ }
+ if (!pdfDocument) {
+ return;
+ }
+ this.pdfDocument = pdfDocument;
+ this.url = url;
+ this._dataAvailableCapability.resolve();
+ }
+ setFileSize(fileSize) {
+ if (typeof fileSize === 'number' && fileSize > 0) {
+ this.maybeFileSize = fileSize;
+ }
+ }
+ _reset() {
+ this.pdfDocument = null;
+ this.url = null;
+ this.maybeFileSize = 0;
+ delete this.fieldData;
+ this._dataAvailableCapability = (0, _pdfjsLib.createPromiseCapability)();
+ }
+ _updateUI(reset = false) {
+ if (reset || !this.fieldData) {
+ for (let id in this.fields) {
+ this.fields[id].textContent = DEFAULT_FIELD_CONTENT;
+ }
+ return;
+ }
+ if (this.overlayManager.active !== this.overlayName) {
+ return;
+ }
+ for (let id in this.fields) {
+ let content = this.fieldData[id];
+ this.fields[id].textContent = content || content === 0 ? content : DEFAULT_FIELD_CONTENT;
+ }
+ }
+ _parseFileSize(fileSize = 0) {
+ let kb = fileSize / 1024;
+ if (!kb) {
+ return Promise.resolve(undefined);
+ } else if (kb < 1024) {
+ return this.l10n.get('document_properties_kb', {
+ size_kb: (+kb.toPrecision(3)).toLocaleString(),
+ size_b: fileSize.toLocaleString()
+ }, '{{size_kb}} KB ({{size_b}} bytes)');
+ }
+ return this.l10n.get('document_properties_mb', {
+ size_mb: (+(kb / 1024).toPrecision(3)).toLocaleString(),
+ size_b: fileSize.toLocaleString()
+ }, '{{size_mb}} MB ({{size_b}} bytes)');
+ }
+ _parseDate(inputDate) {
+ if (!inputDate) {
+ return;
+ }
+ let dateToParse = inputDate;
+ if (dateToParse.substring(0, 2) === 'D:') {
+ dateToParse = dateToParse.substring(2);
+ }
+ let year = parseInt(dateToParse.substring(0, 4), 10);
+ let month = parseInt(dateToParse.substring(4, 6), 10) - 1;
+ let day = parseInt(dateToParse.substring(6, 8), 10);
+ let hours = parseInt(dateToParse.substring(8, 10), 10);
+ let minutes = parseInt(dateToParse.substring(10, 12), 10);
+ let seconds = parseInt(dateToParse.substring(12, 14), 10);
+ let utRel = dateToParse.substring(14, 15);
+ let offsetHours = parseInt(dateToParse.substring(15, 17), 10);
+ let offsetMinutes = parseInt(dateToParse.substring(18, 20), 10);
+ if (utRel === '-') {
+ hours += offsetHours;
+ minutes += offsetMinutes;
+ } else if (utRel === '+') {
+ hours -= offsetHours;
+ minutes -= offsetMinutes;
+ }
+ let date = new Date(Date.UTC(year, month, day, hours, minutes, seconds));
+ let dateString = date.toLocaleDateString();
+ let timeString = date.toLocaleTimeString();
+ return this.l10n.get('document_properties_date_string', {
+ date: dateString,
+ time: timeString
+ }, '{{date}}, {{time}}');
+ }
+}
+exports.PDFDocumentProperties = PDFDocumentProperties;
+
+/***/ }),
+/* 15 */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.PDFFindBar = undefined;
+
+var _pdf_find_controller = __webpack_require__(7);
+
+var _ui_utils = __webpack_require__(0);
+
+class PDFFindBar {
+ constructor(options, l10n = _ui_utils.NullL10n) {
+ this.opened = false;
+ this.bar = options.bar || null;
+ this.toggleButton = options.toggleButton || null;
+ this.findField = options.findField || null;
+ this.highlightAll = options.highlightAllCheckbox || null;
+ this.caseSensitive = options.caseSensitiveCheckbox || null;
+ this.findMsg = options.findMsg || null;
+ this.findResultsCount = options.findResultsCount || null;
+ this.findStatusIcon = options.findStatusIcon || null;
+ this.findPreviousButton = options.findPreviousButton || null;
+ this.findNextButton = options.findNextButton || null;
+ this.findController = options.findController || null;
+ this.eventBus = options.eventBus;
+ this.l10n = l10n;
+ if (this.findController === null) {
+ throw new Error('PDFFindBar cannot be used without a ' + 'PDFFindController instance.');
+ }
+ this.toggleButton.addEventListener('click', () => {
+ this.toggle();
+ });
+ this.findField.addEventListener('input', () => {
+ this.dispatchEvent('');
+ });
+ this.bar.addEventListener('keydown', e => {
+ switch (e.keyCode) {
+ case 13:
+ if (e.target === this.findField) {
+ this.dispatchEvent('again', e.shiftKey);
+ }
+ break;
+ case 27:
+ this.close();
+ break;
+ }
+ });
+ this.findPreviousButton.addEventListener('click', () => {
+ this.dispatchEvent('again', true);
+ });
+ this.findNextButton.addEventListener('click', () => {
+ this.dispatchEvent('again', false);
+ });
+ this.highlightAll.addEventListener('click', () => {
+ this.dispatchEvent('highlightallchange');
+ });
+ this.caseSensitive.addEventListener('click', () => {
+ this.dispatchEvent('casesensitivitychange');
+ });
+ this.eventBus.on('resize', this._adjustWidth.bind(this));
+ }
+ reset() {
+ this.updateUIState();
+ }
+ dispatchEvent(type, findPrev) {
+ this.eventBus.dispatch('find', {
+ source: this,
+ type,
+ query: this.findField.value,
+ caseSensitive: this.caseSensitive.checked,
+ phraseSearch: true,
+ highlightAll: this.highlightAll.checked,
+ findPrevious: findPrev
+ });
+ }
+ updateUIState(state, previous, matchCount) {
+ let notFound = false;
+ let findMsg = '';
+ let status = '';
+ switch (state) {
+ case _pdf_find_controller.FindState.FOUND:
+ break;
+ case _pdf_find_controller.FindState.PENDING:
+ status = 'pending';
+ break;
+ case _pdf_find_controller.FindState.NOT_FOUND:
+ findMsg = this.l10n.get('find_not_found', null, 'Phrase not found');
+ notFound = true;
+ break;
+ case _pdf_find_controller.FindState.WRAPPED:
+ if (previous) {
+ findMsg = this.l10n.get('find_reached_top', null, 'Reached top of document, continued from bottom');
+ } else {
+ findMsg = this.l10n.get('find_reached_bottom', null, 'Reached end of document, continued from top');
+ }
+ break;
+ }
+ if (notFound) {
+ this.findField.classList.add('notFound');
+ } else {
+ this.findField.classList.remove('notFound');
+ }
+ this.findField.setAttribute('data-status', status);
+ Promise.resolve(findMsg).then(msg => {
+ this.findMsg.textContent = msg;
+ this._adjustWidth();
+ });
+ this.updateResultsCount(matchCount);
+ }
+ updateResultsCount(matchCount) {
+ if (!this.findResultsCount) {
+ return;
+ }
+ if (!matchCount) {
+ this.findResultsCount.classList.add('hidden');
+ this.findResultsCount.textContent = '';
+ } else {
+ this.findResultsCount.textContent = matchCount.toLocaleString();
+ this.findResultsCount.classList.remove('hidden');
+ }
+ this._adjustWidth();
+ }
+ open() {
+ if (!this.opened) {
+ this.opened = true;
+ this.toggleButton.classList.add('toggled');
+ this.bar.classList.remove('hidden');
+ }
+ this.findField.select();
+ this.findField.focus();
+ this._adjustWidth();
+ }
+ close() {
+ if (!this.opened) {
+ return;
+ }
+ this.opened = false;
+ this.toggleButton.classList.remove('toggled');
+ this.bar.classList.add('hidden');
+ this.findController.active = false;
+ }
+ toggle() {
+ if (this.opened) {
+ this.close();
+ } else {
+ this.open();
+ }
+ }
+ _adjustWidth() {
+ if (!this.opened) {
+ return;
+ }
+ this.bar.classList.remove('wrapContainers');
+ let findbarHeight = this.bar.clientHeight;
+ let inputContainerHeight = this.bar.firstElementChild.clientHeight;
+ if (findbarHeight > inputContainerHeight) {
+ this.bar.classList.add('wrapContainers');
+ }
+ }
+}
+exports.PDFFindBar = PDFFindBar;
+
+/***/ }),
+/* 16 */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.isDestsEqual = exports.PDFHistory = undefined;
+
+var _ui_utils = __webpack_require__(0);
+
+var _dom_events = __webpack_require__(2);
+
+const HASH_CHANGE_TIMEOUT = 1000;
+const POSITION_UPDATED_THRESHOLD = 50;
+const UPDATE_VIEWAREA_TIMEOUT = 1000;
+function getCurrentHash() {
+ return document.location.hash;
+}
+function parseCurrentHash(linkService) {
+ let hash = unescape(getCurrentHash()).substring(1);
+ let params = (0, _ui_utils.parseQueryString)(hash);
+ let page = params.page | 0;
+ if (!(Number.isInteger(page) && page > 0 && page <= linkService.pagesCount)) {
+ page = null;
+ }
+ return {
+ hash,
+ page,
+ rotation: linkService.rotation
+ };
+}
+class PDFHistory {
+ constructor({ linkService, eventBus }) {
+ this.linkService = linkService;
+ this.eventBus = eventBus || (0, _dom_events.getGlobalEventBus)();
+ this.initialized = false;
+ this.initialBookmark = null;
+ this.initialRotation = null;
+ this._boundEvents = Object.create(null);
+ this._isViewerInPresentationMode = false;
+ this._isPagesLoaded = false;
+ this.eventBus.on('presentationmodechanged', evt => {
+ this._isViewerInPresentationMode = evt.active || evt.switchInProgress;
+ });
+ this.eventBus.on('pagesloaded', evt => {
+ this._isPagesLoaded = !!evt.pagesCount;
+ });
+ }
+ initialize(fingerprint, resetHistory = false) {
+ if (!fingerprint || typeof fingerprint !== 'string') {
+ console.error('PDFHistory.initialize: The "fingerprint" must be a non-empty string.');
+ return;
+ }
+ let reInitialized = this.initialized && this.fingerprint !== fingerprint;
+ this.fingerprint = fingerprint;
+ if (!this.initialized) {
+ this._bindEvents();
+ }
+ let state = window.history.state;
+ this.initialized = true;
+ this.initialBookmark = null;
+ this.initialRotation = null;
+ this._popStateInProgress = false;
+ this._blockHashChange = 0;
+ this._currentHash = getCurrentHash();
+ this._numPositionUpdates = 0;
+ this._currentUid = this._uid = 0;
+ this._destination = null;
+ this._position = null;
+ if (!this._isValidState(state) || resetHistory) {
+ let { hash, page, rotation } = parseCurrentHash(this.linkService);
+ if (!hash || reInitialized || resetHistory) {
+ this._pushOrReplaceState(null, true);
+ return;
+ }
+ this._pushOrReplaceState({
+ hash,
+ page,
+ rotation
+ }, true);
+ return;
+ }
+ let destination = state.destination;
+ this._updateInternalState(destination, state.uid, true);
+ if (destination.rotation !== undefined) {
+ this.initialRotation = destination.rotation;
+ }
+ if (destination.dest) {
+ this.initialBookmark = JSON.stringify(destination.dest);
+ this._destination.page = null;
+ } else if (destination.hash) {
+ this.initialBookmark = destination.hash;
+ } else if (destination.page) {
+ this.initialBookmark = `page=${destination.page}`;
+ }
+ }
+ push({ namedDest, explicitDest, pageNumber }) {
+ if (!this.initialized) {
+ return;
+ }
+ if (namedDest && typeof namedDest !== 'string' || !(explicitDest instanceof Array) || !(Number.isInteger(pageNumber) && pageNumber > 0 && pageNumber <= this.linkService.pagesCount)) {
+ console.error('PDFHistory.push: Invalid parameters.');
+ return;
+ }
+ let hash = namedDest || JSON.stringify(explicitDest);
+ if (!hash) {
+ return;
+ }
+ let forceReplace = false;
+ if (this._destination && (this._destination.hash === hash || isDestsEqual(this._destination.dest, explicitDest))) {
+ if (this._destination.page) {
+ return;
+ }
+ forceReplace = true;
+ }
+ if (this._popStateInProgress && !forceReplace) {
+ return;
+ }
+ this._pushOrReplaceState({
+ dest: explicitDest,
+ hash,
+ page: pageNumber,
+ rotation: this.linkService.rotation
+ }, forceReplace);
+ if (!this._popStateInProgress) {
+ this._popStateInProgress = true;
+ Promise.resolve().then(() => {
+ this._popStateInProgress = false;
+ });
+ }
+ }
+ pushCurrentPosition() {
+ if (!this.initialized || this._popStateInProgress) {
+ return;
+ }
+ this._tryPushCurrentPosition();
+ }
+ back() {
+ if (!this.initialized || this._popStateInProgress) {
+ return;
+ }
+ let state = window.history.state;
+ if (this._isValidState(state) && state.uid > 0) {
+ window.history.back();
+ }
+ }
+ forward() {
+ if (!this.initialized || this._popStateInProgress) {
+ return;
+ }
+ let state = window.history.state;
+ if (this._isValidState(state) && state.uid < this._uid - 1) {
+ window.history.forward();
+ }
+ }
+ get popStateInProgress() {
+ return this.initialized && (this._popStateInProgress || this._blockHashChange > 0);
+ }
+ _pushOrReplaceState(destination, forceReplace = false) {
+ let shouldReplace = forceReplace || !this._destination;
+ let newState = {
+ fingerprint: this.fingerprint,
+ uid: shouldReplace ? this._currentUid : this._uid,
+ destination
+ };
+ this._updateInternalState(destination, newState.uid);
+ if (shouldReplace) {
+ window.history.replaceState(newState, '');
+ } else {
+ window.history.pushState(newState, '');
+ }
+ }
+ _tryPushCurrentPosition(temporary = false) {
+ if (!this._position) {
+ return;
+ }
+ let position = this._position;
+ if (temporary) {
+ position = (0, _ui_utils.cloneObj)(this._position);
+ position.temporary = true;
+ }
+ if (!this._destination) {
+ this._pushOrReplaceState(position);
+ return;
+ }
+ if (this._destination.temporary) {
+ this._pushOrReplaceState(position, true);
+ return;
+ }
+ if (this._destination.hash === position.hash) {
+ return;
+ }
+ if (!this._destination.page && (POSITION_UPDATED_THRESHOLD <= 0 || this._numPositionUpdates <= POSITION_UPDATED_THRESHOLD)) {
+ return;
+ }
+ let forceReplace = false;
+ if (this._destination.page === position.first || this._destination.page === position.page) {
+ if (this._destination.dest || !this._destination.first) {
+ return;
+ }
+ forceReplace = true;
+ }
+ this._pushOrReplaceState(position, forceReplace);
+ }
+ _isValidState(state) {
+ if (!state) {
+ return false;
+ }
+ if (state.fingerprint !== this.fingerprint) {
+ return false;
+ }
+ if (!Number.isInteger(state.uid) || state.uid < 0) {
+ return false;
+ }
+ if (state.destination === null || typeof state.destination !== 'object') {
+ return false;
+ }
+ return true;
+ }
+ _updateInternalState(destination, uid, removeTemporary = false) {
+ if (this._updateViewareaTimeout) {
+ clearTimeout(this._updateViewareaTimeout);
+ this._updateViewareaTimeout = null;
+ }
+ if (removeTemporary && destination && destination.temporary) {
+ delete destination.temporary;
+ }
+ this._destination = destination;
+ this._currentUid = uid;
+ this._uid = this._currentUid + 1;
+ this._numPositionUpdates = 0;
+ }
+ _updateViewarea({ location }) {
+ if (this._updateViewareaTimeout) {
+ clearTimeout(this._updateViewareaTimeout);
+ this._updateViewareaTimeout = null;
+ }
+ this._position = {
+ hash: this._isViewerInPresentationMode ? `page=${location.pageNumber}` : location.pdfOpenParams.substring(1),
+ page: this.linkService.page,
+ first: location.pageNumber,
+ rotation: location.rotation
+ };
+ if (this._popStateInProgress) {
+ return;
+ }
+ if (POSITION_UPDATED_THRESHOLD > 0 && this._isPagesLoaded && this._destination && !this._destination.page) {
+ this._numPositionUpdates++;
+ }
+ if (UPDATE_VIEWAREA_TIMEOUT > 0) {
+ this._updateViewareaTimeout = setTimeout(() => {
+ if (!this._popStateInProgress) {
+ this._tryPushCurrentPosition(true);
+ }
+ this._updateViewareaTimeout = null;
+ }, UPDATE_VIEWAREA_TIMEOUT);
+ }
+ }
+ _popState({ state }) {
+ let newHash = getCurrentHash(),
+ hashChanged = this._currentHash !== newHash;
+ this._currentHash = newHash;
+ if (!state || false) {
+ this._currentUid = this._uid;
+ let { hash, page, rotation } = parseCurrentHash(this.linkService);
+ this._pushOrReplaceState({
+ hash,
+ page,
+ rotation
+ }, true);
+ return;
+ }
+ if (!this._isValidState(state)) {
+ return;
+ }
+ this._popStateInProgress = true;
+ if (hashChanged) {
+ this._blockHashChange++;
+ (0, _ui_utils.waitOnEventOrTimeout)({
+ target: window,
+ name: 'hashchange',
+ delay: HASH_CHANGE_TIMEOUT
+ }).then(() => {
+ this._blockHashChange--;
+ });
+ }
+ let destination = state.destination;
+ this._updateInternalState(destination, state.uid, true);
+ if ((0, _ui_utils.isValidRotation)(destination.rotation)) {
+ this.linkService.rotation = destination.rotation;
+ }
+ if (destination.dest) {
+ this.linkService.navigateTo(destination.dest);
+ } else if (destination.hash) {
+ this.linkService.setHash(destination.hash);
+ } else if (destination.page) {
+ this.linkService.page = destination.page;
+ }
+ Promise.resolve().then(() => {
+ this._popStateInProgress = false;
+ });
+ }
+ _bindEvents() {
+ let { _boundEvents, eventBus } = this;
+ _boundEvents.updateViewarea = this._updateViewarea.bind(this);
+ _boundEvents.popState = this._popState.bind(this);
+ _boundEvents.pageHide = evt => {
+ if (!this._destination) {
+ this._tryPushCurrentPosition();
+ }
+ };
+ eventBus.on('updateviewarea', _boundEvents.updateViewarea);
+ window.addEventListener('popstate', _boundEvents.popState);
+ window.addEventListener('pagehide', _boundEvents.pageHide);
+ }
+}
+function isDestsEqual(firstDest, secondDest) {
+ function isEntryEqual(first, second) {
+ if (typeof first !== typeof second) {
+ return false;
+ }
+ if (first instanceof Array || second instanceof Array) {
+ return false;
+ }
+ if (first !== null && typeof first === 'object' && second !== null) {
+ if (Object.keys(first).length !== Object.keys(second).length) {
+ return false;
+ }
+ for (var key in first) {
+ if (!isEntryEqual(first[key], second[key])) {
+ return false;
+ }
+ }
+ return true;
+ }
+ return first === second || Number.isNaN(first) && Number.isNaN(second);
+ }
+ if (!(firstDest instanceof Array && secondDest instanceof Array)) {
+ return false;
+ }
+ if (firstDest.length !== secondDest.length) {
+ return false;
+ }
+ for (let i = 0, ii = firstDest.length; i < ii; i++) {
+ if (!isEntryEqual(firstDest[i], secondDest[i])) {
+ return false;
+ }
+ }
+ return true;
+}
+exports.PDFHistory = PDFHistory;
+exports.isDestsEqual = isDestsEqual;
+
+/***/ }),
+/* 17 */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.PDFOutlineViewer = undefined;
+
+var _pdfjsLib = __webpack_require__(1);
+
+const DEFAULT_TITLE = '\u2013';
+class PDFOutlineViewer {
+ constructor({ container, linkService, eventBus }) {
+ this.container = container;
+ this.linkService = linkService;
+ this.eventBus = eventBus;
+ this.reset();
+ }
+ reset() {
+ this.outline = null;
+ this.lastToggleIsShow = true;
+ this.container.textContent = '';
+ this.container.classList.remove('outlineWithDeepNesting');
+ }
+ _dispatchEvent(outlineCount) {
+ this.eventBus.dispatch('outlineloaded', {
+ source: this,
+ outlineCount
+ });
+ }
+ _bindLink(element, item) {
+ if (item.url) {
+ (0, _pdfjsLib.addLinkAttributes)(element, {
+ url: item.url,
+ target: item.newWindow ? _pdfjsLib.PDFJS.LinkTarget.BLANK : undefined
+ });
+ return;
+ }
+ let destination = item.dest;
+ element.href = this.linkService.getDestinationHash(destination);
+ element.onclick = () => {
+ if (destination) {
+ this.linkService.navigateTo(destination);
+ }
+ return false;
+ };
+ }
+ _setStyles(element, item) {
+ let styleStr = '';
+ if (item.bold) {
+ styleStr += 'font-weight: bold;';
+ }
+ if (item.italic) {
+ styleStr += 'font-style: italic;';
+ }
+ if (styleStr) {
+ element.setAttribute('style', styleStr);
+ }
+ }
+ _addToggleButton(div) {
+ let toggler = document.createElement('div');
+ toggler.className = 'outlineItemToggler';
+ toggler.onclick = evt => {
+ evt.stopPropagation();
+ toggler.classList.toggle('outlineItemsHidden');
+ if (evt.shiftKey) {
+ let shouldShowAll = !toggler.classList.contains('outlineItemsHidden');
+ this._toggleOutlineItem(div, shouldShowAll);
+ }
+ };
+ div.insertBefore(toggler, div.firstChild);
+ }
+ _toggleOutlineItem(root, show) {
+ this.lastToggleIsShow = show;
+ let togglers = root.querySelectorAll('.outlineItemToggler');
+ for (let i = 0, ii = togglers.length; i < ii; ++i) {
+ togglers[i].classList[show ? 'remove' : 'add']('outlineItemsHidden');
+ }
+ }
+ toggleOutlineTree() {
+ if (!this.outline) {
+ return;
+ }
+ this._toggleOutlineItem(this.container, !this.lastToggleIsShow);
+ }
+ render({ outline }) {
+ let outlineCount = 0;
+ if (this.outline) {
+ this.reset();
+ }
+ this.outline = outline || null;
+ if (!outline) {
+ this._dispatchEvent(outlineCount);
+ return;
+ }
+ let fragment = document.createDocumentFragment();
+ let queue = [{
+ parent: fragment,
+ items: this.outline
+ }];
+ let hasAnyNesting = false;
+ while (queue.length > 0) {
+ let levelData = queue.shift();
+ for (let i = 0, len = levelData.items.length; i < len; i++) {
+ let item = levelData.items[i];
+ let div = document.createElement('div');
+ div.className = 'outlineItem';
+ let element = document.createElement('a');
+ this._bindLink(element, item);
+ this._setStyles(element, item);
+ element.textContent = (0, _pdfjsLib.removeNullCharacters)(item.title) || DEFAULT_TITLE;
+ div.appendChild(element);
+ if (item.items.length > 0) {
+ hasAnyNesting = true;
+ this._addToggleButton(div);
+ let itemsDiv = document.createElement('div');
+ itemsDiv.className = 'outlineItems';
+ div.appendChild(itemsDiv);
+ queue.push({
+ parent: itemsDiv,
+ items: item.items
+ });
+ }
+ levelData.parent.appendChild(div);
+ outlineCount++;
+ }
+ }
+ if (hasAnyNesting) {
+ this.container.classList.add('outlineWithDeepNesting');
+ }
+ this.container.appendChild(fragment);
+ this._dispatchEvent(outlineCount);
+ }
+}
+exports.PDFOutlineViewer = PDFOutlineViewer;
+
+/***/ }),
+/* 18 */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.PDFPresentationMode = undefined;
+
+var _ui_utils = __webpack_require__(0);
+
+const DELAY_BEFORE_RESETTING_SWITCH_IN_PROGRESS = 1500;
+const DELAY_BEFORE_HIDING_CONTROLS = 3000;
+const ACTIVE_SELECTOR = 'pdfPresentationMode';
+const CONTROLS_SELECTOR = 'pdfPresentationModeControls';
+const MOUSE_SCROLL_COOLDOWN_TIME = 50;
+const PAGE_SWITCH_THRESHOLD = 0.1;
+const SWIPE_MIN_DISTANCE_THRESHOLD = 50;
+const SWIPE_ANGLE_THRESHOLD = Math.PI / 6;
+class PDFPresentationMode {
+ constructor({ container, viewer = null, pdfViewer, eventBus, contextMenuItems = null }) {
+ this.container = container;
+ this.viewer = viewer || container.firstElementChild;
+ this.pdfViewer = pdfViewer;
+ this.eventBus = eventBus;
+ this.active = false;
+ this.args = null;
+ this.contextMenuOpen = false;
+ this.mouseScrollTimeStamp = 0;
+ this.mouseScrollDelta = 0;
+ this.touchSwipeState = null;
+ if (contextMenuItems) {
+ contextMenuItems.contextFirstPage.addEventListener('click', () => {
+ this.contextMenuOpen = false;
+ this.eventBus.dispatch('firstpage');
+ });
+ contextMenuItems.contextLastPage.addEventListener('click', () => {
+ this.contextMenuOpen = false;
+ this.eventBus.dispatch('lastpage');
+ });
+ contextMenuItems.contextPageRotateCw.addEventListener('click', () => {
+ this.contextMenuOpen = false;
+ this.eventBus.dispatch('rotatecw');
+ });
+ contextMenuItems.contextPageRotateCcw.addEventListener('click', () => {
+ this.contextMenuOpen = false;
+ this.eventBus.dispatch('rotateccw');
+ });
+ }
+ }
+ request() {
+ if (this.switchInProgress || this.active || !this.viewer.hasChildNodes()) {
+ return false;
+ }
+ this._addFullscreenChangeListeners();
+ this._setSwitchInProgress();
+ this._notifyStateChange();
+ if (this.container.requestFullscreen) {
+ this.container.requestFullscreen();
+ } else if (this.container.mozRequestFullScreen) {
+ this.container.mozRequestFullScreen();
+ } else if (this.container.webkitRequestFullscreen) {
+ this.container.webkitRequestFullscreen(Element.ALLOW_KEYBOARD_INPUT);
+ } else if (this.container.msRequestFullscreen) {
+ this.container.msRequestFullscreen();
+ } else {
+ return false;
+ }
+ this.args = {
+ page: this.pdfViewer.currentPageNumber,
+ previousScale: this.pdfViewer.currentScaleValue
+ };
+ return true;
+ }
+ _mouseWheel(evt) {
+ if (!this.active) {
+ return;
+ }
+ evt.preventDefault();
+ let delta = (0, _ui_utils.normalizeWheelEventDelta)(evt);
+ let currentTime = new Date().getTime();
+ let storedTime = this.mouseScrollTimeStamp;
+ if (currentTime > storedTime && currentTime - storedTime < MOUSE_SCROLL_COOLDOWN_TIME) {
+ return;
+ }
+ if (this.mouseScrollDelta > 0 && delta < 0 || this.mouseScrollDelta < 0 && delta > 0) {
+ this._resetMouseScrollState();
+ }
+ this.mouseScrollDelta += delta;
+ if (Math.abs(this.mouseScrollDelta) >= PAGE_SWITCH_THRESHOLD) {
+ let totalDelta = this.mouseScrollDelta;
+ this._resetMouseScrollState();
+ let success = totalDelta > 0 ? this._goToPreviousPage() : this._goToNextPage();
+ if (success) {
+ this.mouseScrollTimeStamp = currentTime;
+ }
+ }
+ }
+ get isFullscreen() {
+ return !!(document.fullscreenElement || document.mozFullScreen || document.webkitIsFullScreen || document.msFullscreenElement);
+ }
+ _goToPreviousPage() {
+ let page = this.pdfViewer.currentPageNumber;
+ if (page <= 1) {
+ return false;
+ }
+ this.pdfViewer.currentPageNumber = page - 1;
+ return true;
+ }
+ _goToNextPage() {
+ let page = this.pdfViewer.currentPageNumber;
+ if (page >= this.pdfViewer.pagesCount) {
+ return false;
+ }
+ this.pdfViewer.currentPageNumber = page + 1;
+ return true;
+ }
+ _notifyStateChange() {
+ this.eventBus.dispatch('presentationmodechanged', {
+ source: this,
+ active: this.active,
+ switchInProgress: !!this.switchInProgress
+ });
+ }
+ _setSwitchInProgress() {
+ if (this.switchInProgress) {
+ clearTimeout(this.switchInProgress);
+ }
+ this.switchInProgress = setTimeout(() => {
+ this._removeFullscreenChangeListeners();
+ delete this.switchInProgress;
+ this._notifyStateChange();
+ }, DELAY_BEFORE_RESETTING_SWITCH_IN_PROGRESS);
+ }
+ _resetSwitchInProgress() {
+ if (this.switchInProgress) {
+ clearTimeout(this.switchInProgress);
+ delete this.switchInProgress;
+ }
+ }
+ _enter() {
+ this.active = true;
+ this._resetSwitchInProgress();
+ this._notifyStateChange();
+ this.container.classList.add(ACTIVE_SELECTOR);
+ setTimeout(() => {
+ this.pdfViewer.currentPageNumber = this.args.page;
+ this.pdfViewer.currentScaleValue = 'page-fit';
+ }, 0);
+ this._addWindowListeners();
+ this._showControls();
+ this.contextMenuOpen = false;
+ this.container.setAttribute('contextmenu', 'viewerContextMenu');
+ window.getSelection().removeAllRanges();
+ }
+ _exit() {
+ let page = this.pdfViewer.currentPageNumber;
+ this.container.classList.remove(ACTIVE_SELECTOR);
+ setTimeout(() => {
+ this.active = false;
+ this._removeFullscreenChangeListeners();
+ this._notifyStateChange();
+ this.pdfViewer.currentScaleValue = this.args.previousScale;
+ this.pdfViewer.currentPageNumber = page;
+ this.args = null;
+ }, 0);
+ this._removeWindowListeners();
+ this._hideControls();
+ this._resetMouseScrollState();
+ this.container.removeAttribute('contextmenu');
+ this.contextMenuOpen = false;
+ }
+ _mouseDown(evt) {
+ if (this.contextMenuOpen) {
+ this.contextMenuOpen = false;
+ evt.preventDefault();
+ return;
+ }
+ if (evt.button === 0) {
+ let isInternalLink = evt.target.href && evt.target.classList.contains('internalLink');
+ if (!isInternalLink) {
+ evt.preventDefault();
+ if (evt.shiftKey) {
+ this._goToPreviousPage();
+ } else {
+ this._goToNextPage();
+ }
+ }
+ }
+ }
+ _contextMenu() {
+ this.contextMenuOpen = true;
+ }
+ _showControls() {
+ if (this.controlsTimeout) {
+ clearTimeout(this.controlsTimeout);
+ } else {
+ this.container.classList.add(CONTROLS_SELECTOR);
+ }
+ this.controlsTimeout = setTimeout(() => {
+ this.container.classList.remove(CONTROLS_SELECTOR);
+ delete this.controlsTimeout;
+ }, DELAY_BEFORE_HIDING_CONTROLS);
+ }
+ _hideControls() {
+ if (!this.controlsTimeout) {
+ return;
+ }
+ clearTimeout(this.controlsTimeout);
+ this.container.classList.remove(CONTROLS_SELECTOR);
+ delete this.controlsTimeout;
+ }
+ _resetMouseScrollState() {
+ this.mouseScrollTimeStamp = 0;
+ this.mouseScrollDelta = 0;
+ }
+ _touchSwipe(evt) {
+ if (!this.active) {
+ return;
+ }
+ if (evt.touches.length > 1) {
+ this.touchSwipeState = null;
+ return;
+ }
+ switch (evt.type) {
+ case 'touchstart':
+ this.touchSwipeState = {
+ startX: evt.touches[0].pageX,
+ startY: evt.touches[0].pageY,
+ endX: evt.touches[0].pageX,
+ endY: evt.touches[0].pageY
+ };
+ break;
+ case 'touchmove':
+ if (this.touchSwipeState === null) {
+ return;
+ }
+ this.touchSwipeState.endX = evt.touches[0].pageX;
+ this.touchSwipeState.endY = evt.touches[0].pageY;
+ evt.preventDefault();
+ break;
+ case 'touchend':
+ if (this.touchSwipeState === null) {
+ return;
+ }
+ let delta = 0;
+ let dx = this.touchSwipeState.endX - this.touchSwipeState.startX;
+ let dy = this.touchSwipeState.endY - this.touchSwipeState.startY;
+ let absAngle = Math.abs(Math.atan2(dy, dx));
+ if (Math.abs(dx) > SWIPE_MIN_DISTANCE_THRESHOLD && (absAngle <= SWIPE_ANGLE_THRESHOLD || absAngle >= Math.PI - SWIPE_ANGLE_THRESHOLD)) {
+ delta = dx;
+ } else if (Math.abs(dy) > SWIPE_MIN_DISTANCE_THRESHOLD && Math.abs(absAngle - Math.PI / 2) <= SWIPE_ANGLE_THRESHOLD) {
+ delta = dy;
+ }
+ if (delta > 0) {
+ this._goToPreviousPage();
+ } else if (delta < 0) {
+ this._goToNextPage();
+ }
+ break;
+ }
+ }
+ _addWindowListeners() {
+ this.showControlsBind = this._showControls.bind(this);
+ this.mouseDownBind = this._mouseDown.bind(this);
+ this.mouseWheelBind = this._mouseWheel.bind(this);
+ this.resetMouseScrollStateBind = this._resetMouseScrollState.bind(this);
+ this.contextMenuBind = this._contextMenu.bind(this);
+ this.touchSwipeBind = this._touchSwipe.bind(this);
+ window.addEventListener('mousemove', this.showControlsBind);
+ window.addEventListener('mousedown', this.mouseDownBind);
+ window.addEventListener('wheel', this.mouseWheelBind);
+ window.addEventListener('keydown', this.resetMouseScrollStateBind);
+ window.addEventListener('contextmenu', this.contextMenuBind);
+ window.addEventListener('touchstart', this.touchSwipeBind);
+ window.addEventListener('touchmove', this.touchSwipeBind);
+ window.addEventListener('touchend', this.touchSwipeBind);
+ }
+ _removeWindowListeners() {
+ window.removeEventListener('mousemove', this.showControlsBind);
+ window.removeEventListener('mousedown', this.mouseDownBind);
+ window.removeEventListener('wheel', this.mouseWheelBind);
+ window.removeEventListener('keydown', this.resetMouseScrollStateBind);
+ window.removeEventListener('contextmenu', this.contextMenuBind);
+ window.removeEventListener('touchstart', this.touchSwipeBind);
+ window.removeEventListener('touchmove', this.touchSwipeBind);
+ window.removeEventListener('touchend', this.touchSwipeBind);
+ delete this.showControlsBind;
+ delete this.mouseDownBind;
+ delete this.mouseWheelBind;
+ delete this.resetMouseScrollStateBind;
+ delete this.contextMenuBind;
+ delete this.touchSwipeBind;
+ }
+ _fullscreenChange() {
+ if (this.isFullscreen) {
+ this._enter();
+ } else {
+ this._exit();
+ }
+ }
+ _addFullscreenChangeListeners() {
+ this.fullscreenChangeBind = this._fullscreenChange.bind(this);
+ window.addEventListener('fullscreenchange', this.fullscreenChangeBind);
+ window.addEventListener('mozfullscreenchange', this.fullscreenChangeBind);
+ }
+ _removeFullscreenChangeListeners() {
+ window.removeEventListener('fullscreenchange', this.fullscreenChangeBind);
+ window.removeEventListener('mozfullscreenchange', this.fullscreenChangeBind);
+ delete this.fullscreenChangeBind;
+ }
+}
+exports.PDFPresentationMode = PDFPresentationMode;
+
+/***/ }),
+/* 19 */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.PDFThumbnailViewer = undefined;
+
+var _ui_utils = __webpack_require__(0);
+
+var _pdf_thumbnail_view = __webpack_require__(20);
+
+const THUMBNAIL_SCROLL_MARGIN = -19;
+class PDFThumbnailViewer {
+ constructor({ container, linkService, renderingQueue, l10n = _ui_utils.NullL10n }) {
+ this.container = container;
+ this.linkService = linkService;
+ this.renderingQueue = renderingQueue;
+ this.l10n = l10n;
+ this.scroll = (0, _ui_utils.watchScroll)(this.container, this._scrollUpdated.bind(this));
+ this._resetView();
+ }
+ _scrollUpdated() {
+ this.renderingQueue.renderHighestPriority();
+ }
+ getThumbnail(index) {
+ return this._thumbnails[index];
+ }
+ _getVisibleThumbs() {
+ return (0, _ui_utils.getVisibleElements)(this.container, this._thumbnails);
+ }
+ scrollThumbnailIntoView(page) {
+ let selected = document.querySelector('.thumbnail.selected');
+ if (selected) {
+ selected.classList.remove('selected');
+ }
+ let thumbnail = document.querySelector('div.thumbnail[data-page-number="' + page + '"]');
+ if (thumbnail) {
+ thumbnail.classList.add('selected');
+ }
+ let visibleThumbs = this._getVisibleThumbs();
+ let numVisibleThumbs = visibleThumbs.views.length;
+ if (numVisibleThumbs > 0) {
+ let first = visibleThumbs.first.id;
+ let last = numVisibleThumbs > 1 ? visibleThumbs.last.id : first;
+ if (page <= first || page >= last) {
+ (0, _ui_utils.scrollIntoView)(thumbnail, { top: THUMBNAIL_SCROLL_MARGIN });
+ }
+ }
+ }
+ get pagesRotation() {
+ return this._pagesRotation;
+ }
+ set pagesRotation(rotation) {
+ if (!(0, _ui_utils.isValidRotation)(rotation)) {
+ throw new Error('Invalid thumbnails rotation angle.');
+ }
+ if (!this.pdfDocument) {
+ return;
+ }
+ if (this._pagesRotation === rotation) {
+ return;
+ }
+ this._pagesRotation = rotation;
+ for (let i = 0, ii = this._thumbnails.length; i < ii; i++) {
+ this._thumbnails[i].update(rotation);
+ }
+ }
+ cleanup() {
+ _pdf_thumbnail_view.PDFThumbnailView.cleanup();
+ }
+ _resetView() {
+ this._thumbnails = [];
+ this._pageLabels = null;
+ this._pagesRotation = 0;
+ this._pagesRequests = [];
+ this.container.textContent = '';
+ }
+ setDocument(pdfDocument) {
+ if (this.pdfDocument) {
+ this._cancelRendering();
+ this._resetView();
+ }
+ this.pdfDocument = pdfDocument;
+ if (!pdfDocument) {
+ return;
+ }
+ pdfDocument.getPage(1).then(firstPage => {
+ let pagesCount = pdfDocument.numPages;
+ let viewport = firstPage.getViewport(1.0);
+ for (let pageNum = 1; pageNum <= pagesCount; ++pageNum) {
+ let thumbnail = new _pdf_thumbnail_view.PDFThumbnailView({
+ container: this.container,
+ id: pageNum,
+ defaultViewport: viewport.clone(),
+ linkService: this.linkService,
+ renderingQueue: this.renderingQueue,
+ disableCanvasToImageConversion: false,
+ l10n: this.l10n
+ });
+ this._thumbnails.push(thumbnail);
+ }
+ }).catch(reason => {
+ console.error('Unable to initialize thumbnail viewer', reason);
+ });
+ }
+ _cancelRendering() {
+ for (let i = 0, ii = this._thumbnails.length; i < ii; i++) {
+ if (this._thumbnails[i]) {
+ this._thumbnails[i].cancelRendering();
+ }
+ }
+ }
+ setPageLabels(labels) {
+ if (!this.pdfDocument) {
+ return;
+ }
+ if (!labels) {
+ this._pageLabels = null;
+ } else if (!(labels instanceof Array && this.pdfDocument.numPages === labels.length)) {
+ this._pageLabels = null;
+ console.error('PDFThumbnailViewer_setPageLabels: Invalid page labels.');
+ } else {
+ this._pageLabels = labels;
+ }
+ for (let i = 0, ii = this._thumbnails.length; i < ii; i++) {
+ let label = this._pageLabels && this._pageLabels[i];
+ this._thumbnails[i].setPageLabel(label);
+ }
+ }
+ _ensurePdfPageLoaded(thumbView) {
+ if (thumbView.pdfPage) {
+ return Promise.resolve(thumbView.pdfPage);
+ }
+ let pageNumber = thumbView.id;
+ if (this._pagesRequests[pageNumber]) {
+ return this._pagesRequests[pageNumber];
+ }
+ let promise = this.pdfDocument.getPage(pageNumber).then(pdfPage => {
+ thumbView.setPdfPage(pdfPage);
+ this._pagesRequests[pageNumber] = null;
+ return pdfPage;
+ }).catch(reason => {
+ console.error('Unable to get page for thumb view', reason);
+ this._pagesRequests[pageNumber] = null;
+ });
+ this._pagesRequests[pageNumber] = promise;
+ return promise;
+ }
+ forceRendering() {
+ let visibleThumbs = this._getVisibleThumbs();
+ let thumbView = this.renderingQueue.getHighestPriority(visibleThumbs, this._thumbnails, this.scroll.down);
+ if (thumbView) {
+ this._ensurePdfPageLoaded(thumbView).then(() => {
+ this.renderingQueue.renderView(thumbView);
+ });
+ return true;
+ }
+ return false;
+ }
+}
+exports.PDFThumbnailViewer = PDFThumbnailViewer;
+
+/***/ }),
+/* 20 */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.PDFThumbnailView = undefined;
var _pdfjsLib = __webpack_require__(1);
var _ui_utils = __webpack_require__(0);
var _pdf_rendering_queue = __webpack_require__(3);
-var _annotation_layer_builder = __webpack_require__(12);
+const MAX_NUM_SCALING_STEPS = 3;
+const THUMBNAIL_CANVAS_BORDER_WIDTH = 1;
+const THUMBNAIL_WIDTH = 98;
+const TempImageFactory = function TempImageFactoryClosure() {
+ let tempCanvasCache = null;
+ return {
+ getCanvas(width, height) {
+ let tempCanvas = tempCanvasCache;
+ if (!tempCanvas) {
+ tempCanvas = document.createElement('canvas');
+ tempCanvasCache = tempCanvas;
+ }
+ tempCanvas.width = width;
+ tempCanvas.height = height;
+ tempCanvas.mozOpaque = true;
+ let ctx = tempCanvas.getContext('2d', { alpha: false });
+ ctx.save();
+ ctx.fillStyle = 'rgb(255, 255, 255)';
+ ctx.fillRect(0, 0, width, height);
+ ctx.restore();
+ return tempCanvas;
+ },
+ destroyCanvas() {
+ let tempCanvas = tempCanvasCache;
+ if (tempCanvas) {
+ tempCanvas.width = 0;
+ tempCanvas.height = 0;
+ }
+ tempCanvasCache = null;
+ }
+ };
+}();
+class PDFThumbnailView {
+ constructor({ container, id, defaultViewport, linkService, renderingQueue, disableCanvasToImageConversion = false, l10n = _ui_utils.NullL10n }) {
+ this.id = id;
+ this.renderingId = 'thumbnail' + id;
+ this.pageLabel = null;
+ this.pdfPage = null;
+ this.rotation = 0;
+ this.viewport = defaultViewport;
+ this.pdfPageRotate = defaultViewport.rotation;
+ this.linkService = linkService;
+ this.renderingQueue = renderingQueue;
+ this.renderTask = null;
+ this.renderingState = _pdf_rendering_queue.RenderingStates.INITIAL;
+ this.resume = null;
+ this.disableCanvasToImageConversion = disableCanvasToImageConversion;
+ this.pageWidth = this.viewport.width;
+ this.pageHeight = this.viewport.height;
+ this.pageRatio = this.pageWidth / this.pageHeight;
+ this.canvasWidth = THUMBNAIL_WIDTH;
+ this.canvasHeight = this.canvasWidth / this.pageRatio | 0;
+ this.scale = this.canvasWidth / this.pageWidth;
+ this.l10n = l10n;
+ let anchor = document.createElement('a');
+ anchor.href = linkService.getAnchorUrl('#page=' + id);
+ this.l10n.get('thumb_page_title', { page: id }, 'Page {{page}}').then(msg => {
+ anchor.title = msg;
+ });
+ anchor.onclick = function () {
+ linkService.page = id;
+ return false;
+ };
+ this.anchor = anchor;
+ let div = document.createElement('div');
+ div.className = 'thumbnail';
+ div.setAttribute('data-page-number', this.id);
+ this.div = div;
+ if (id === 1) {
+ div.classList.add('selected');
+ }
+ let ring = document.createElement('div');
+ ring.className = 'thumbnailSelectionRing';
+ let borderAdjustment = 2 * THUMBNAIL_CANVAS_BORDER_WIDTH;
+ ring.style.width = this.canvasWidth + borderAdjustment + 'px';
+ ring.style.height = this.canvasHeight + borderAdjustment + 'px';
+ this.ring = ring;
+ div.appendChild(ring);
+ anchor.appendChild(div);
+ container.appendChild(anchor);
+ }
+ setPdfPage(pdfPage) {
+ this.pdfPage = pdfPage;
+ this.pdfPageRotate = pdfPage.rotate;
+ let totalRotation = (this.rotation + this.pdfPageRotate) % 360;
+ this.viewport = pdfPage.getViewport(1, totalRotation);
+ this.reset();
+ }
+ reset() {
+ this.cancelRendering();
+ this.pageWidth = this.viewport.width;
+ this.pageHeight = this.viewport.height;
+ this.pageRatio = this.pageWidth / this.pageHeight;
+ this.canvasHeight = this.canvasWidth / this.pageRatio | 0;
+ this.scale = this.canvasWidth / this.pageWidth;
+ this.div.removeAttribute('data-loaded');
+ let ring = this.ring;
+ let childNodes = ring.childNodes;
+ for (let i = childNodes.length - 1; i >= 0; i--) {
+ ring.removeChild(childNodes[i]);
+ }
+ let borderAdjustment = 2 * THUMBNAIL_CANVAS_BORDER_WIDTH;
+ ring.style.width = this.canvasWidth + borderAdjustment + 'px';
+ ring.style.height = this.canvasHeight + borderAdjustment + 'px';
+ if (this.canvas) {
+ this.canvas.width = 0;
+ this.canvas.height = 0;
+ delete this.canvas;
+ }
+ if (this.image) {
+ this.image.removeAttribute('src');
+ delete this.image;
+ }
+ }
+ update(rotation) {
+ if (typeof rotation !== 'undefined') {
+ this.rotation = rotation;
+ }
+ let totalRotation = (this.rotation + this.pdfPageRotate) % 360;
+ this.viewport = this.viewport.clone({
+ scale: 1,
+ rotation: totalRotation
+ });
+ this.reset();
+ }
+ cancelRendering() {
+ if (this.renderTask) {
+ this.renderTask.cancel();
+ this.renderTask = null;
+ }
+ this.renderingState = _pdf_rendering_queue.RenderingStates.INITIAL;
+ this.resume = null;
+ }
+ _getPageDrawContext(noCtxScale = false) {
+ let canvas = document.createElement('canvas');
+ this.canvas = canvas;
+ canvas.mozOpaque = true;
+ let ctx = canvas.getContext('2d', { alpha: false });
+ let outputScale = (0, _ui_utils.getOutputScale)(ctx);
+ canvas.width = this.canvasWidth * outputScale.sx | 0;
+ canvas.height = this.canvasHeight * outputScale.sy | 0;
+ canvas.style.width = this.canvasWidth + 'px';
+ canvas.style.height = this.canvasHeight + 'px';
+ if (!noCtxScale && outputScale.scaled) {
+ ctx.scale(outputScale.sx, outputScale.sy);
+ }
+ return ctx;
+ }
+ _convertCanvasToImage() {
+ if (!this.canvas) {
+ return;
+ }
+ if (this.renderingState !== _pdf_rendering_queue.RenderingStates.FINISHED) {
+ return;
+ }
+ let id = this.renderingId;
+ let className = 'thumbnailImage';
+ if (this.disableCanvasToImageConversion) {
+ this.canvas.id = id;
+ this.canvas.className = className;
+ this.l10n.get('thumb_page_canvas', { page: this.pageId }, 'Thumbnail of Page {{page}}').then(msg => {
+ this.canvas.setAttribute('aria-label', msg);
+ });
+ this.div.setAttribute('data-loaded', true);
+ this.ring.appendChild(this.canvas);
+ return;
+ }
+ let image = document.createElement('img');
+ image.id = id;
+ image.className = className;
+ this.l10n.get('thumb_page_canvas', { page: this.pageId }, 'Thumbnail of Page {{page}}').then(msg => {
+ image.setAttribute('aria-label', msg);
+ });
+ image.style.width = this.canvasWidth + 'px';
+ image.style.height = this.canvasHeight + 'px';
+ image.src = this.canvas.toDataURL();
+ this.image = image;
+ this.div.setAttribute('data-loaded', true);
+ this.ring.appendChild(image);
+ this.canvas.width = 0;
+ this.canvas.height = 0;
+ delete this.canvas;
+ }
+ draw() {
+ if (this.renderingState !== _pdf_rendering_queue.RenderingStates.INITIAL) {
+ console.error('Must be in new state before drawing');
+ return Promise.resolve(undefined);
+ }
+ this.renderingState = _pdf_rendering_queue.RenderingStates.RUNNING;
+ let renderCapability = (0, _pdfjsLib.createPromiseCapability)();
+ let finishRenderTask = error => {
+ if (renderTask === this.renderTask) {
+ this.renderTask = null;
+ }
+ if (error instanceof _pdfjsLib.RenderingCancelledException) {
+ renderCapability.resolve(undefined);
+ return;
+ }
+ this.renderingState = _pdf_rendering_queue.RenderingStates.FINISHED;
+ this._convertCanvasToImage();
+ if (!error) {
+ renderCapability.resolve(undefined);
+ } else {
+ renderCapability.reject(error);
+ }
+ };
+ let ctx = this._getPageDrawContext();
+ let drawViewport = this.viewport.clone({ scale: this.scale });
+ let renderContinueCallback = cont => {
+ if (!this.renderingQueue.isHighestPriority(this)) {
+ this.renderingState = _pdf_rendering_queue.RenderingStates.PAUSED;
+ this.resume = () => {
+ this.renderingState = _pdf_rendering_queue.RenderingStates.RUNNING;
+ cont();
+ };
+ return;
+ }
+ cont();
+ };
+ let renderContext = {
+ canvasContext: ctx,
+ viewport: drawViewport
+ };
+ let renderTask = this.renderTask = this.pdfPage.render(renderContext);
+ renderTask.onContinue = renderContinueCallback;
+ renderTask.promise.then(function () {
+ finishRenderTask(null);
+ }, function (error) {
+ finishRenderTask(error);
+ });
+ return renderCapability.promise;
+ }
+ setImage(pageView) {
+ if (this.renderingState !== _pdf_rendering_queue.RenderingStates.INITIAL) {
+ return;
+ }
+ let img = pageView.canvas;
+ if (!img) {
+ return;
+ }
+ if (!this.pdfPage) {
+ this.setPdfPage(pageView.pdfPage);
+ }
+ this.renderingState = _pdf_rendering_queue.RenderingStates.FINISHED;
+ let ctx = this._getPageDrawContext(true);
+ let canvas = ctx.canvas;
+ if (img.width <= 2 * canvas.width) {
+ ctx.drawImage(img, 0, 0, img.width, img.height, 0, 0, canvas.width, canvas.height);
+ this._convertCanvasToImage();
+ return;
+ }
+ let reducedWidth = canvas.width << MAX_NUM_SCALING_STEPS;
+ let reducedHeight = canvas.height << MAX_NUM_SCALING_STEPS;
+ let reducedImage = TempImageFactory.getCanvas(reducedWidth, reducedHeight);
+ let reducedImageCtx = reducedImage.getContext('2d');
+ while (reducedWidth > img.width || reducedHeight > img.height) {
+ reducedWidth >>= 1;
+ reducedHeight >>= 1;
+ }
+ reducedImageCtx.drawImage(img, 0, 0, img.width, img.height, 0, 0, reducedWidth, reducedHeight);
+ while (reducedWidth > 2 * canvas.width) {
+ reducedImageCtx.drawImage(reducedImage, 0, 0, reducedWidth, reducedHeight, 0, 0, reducedWidth >> 1, reducedHeight >> 1);
+ reducedWidth >>= 1;
+ reducedHeight >>= 1;
+ }
+ ctx.drawImage(reducedImage, 0, 0, reducedWidth, reducedHeight, 0, 0, canvas.width, canvas.height);
+ this._convertCanvasToImage();
+ }
+ get pageId() {
+ return this.pageLabel !== null ? this.pageLabel : this.id;
+ }
+ setPageLabel(label) {
+ this.pageLabel = typeof label === 'string' ? label : null;
+ this.l10n.get('thumb_page_title', { page: this.pageId }, 'Page {{page}}').then(msg => {
+ this.anchor.title = msg;
+ });
+ if (this.renderingState !== _pdf_rendering_queue.RenderingStates.FINISHED) {
+ return;
+ }
+ this.l10n.get('thumb_page_canvas', { page: this.pageId }, 'Thumbnail of Page {{page}}').then(ariaLabel => {
+ if (this.image) {
+ this.image.setAttribute('aria-label', ariaLabel);
+ } else if (this.disableCanvasToImageConversion && this.canvas) {
+ this.canvas.setAttribute('aria-label', ariaLabel);
+ }
+ });
+ }
+ static cleanup() {
+ TempImageFactory.destroyCanvas();
+ }
+}
+exports.PDFThumbnailView = PDFThumbnailView;
+
+/***/ }),
+/* 21 */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.PDFViewer = undefined;
+
+var _ui_utils = __webpack_require__(0);
+
+var _base_viewer = __webpack_require__(22);
+
+var _pdfjsLib = __webpack_require__(1);
+
+class PDFViewer extends _base_viewer.BaseViewer {
+ get _setDocumentViewerElement() {
+ return (0, _pdfjsLib.shadow)(this, '_setDocumentViewerElement', this.viewer);
+ }
+ _scrollIntoView({ pageDiv, pageSpot = null }) {
+ (0, _ui_utils.scrollIntoView)(pageDiv, pageSpot);
+ }
+ _getVisiblePages() {
+ if (!this.isInPresentationMode) {
+ return (0, _ui_utils.getVisibleElements)(this.container, this._pages, true);
+ }
+ let currentPage = this._pages[this._currentPageNumber - 1];
+ let visible = [{
+ id: currentPage.id,
+ view: currentPage
+ }];
+ return {
+ first: currentPage,
+ last: currentPage,
+ views: visible
+ };
+ }
+ update() {
+ let visible = this._getVisiblePages();
+ let visiblePages = visible.views,
+ numVisiblePages = visiblePages.length;
+ if (numVisiblePages === 0) {
+ return;
+ }
+ this._resizeBuffer(numVisiblePages);
+ this.renderingQueue.renderHighestPriority(visible);
+ let currentId = this._currentPageNumber;
+ let stillFullyVisible = false;
+ for (let i = 0; i < numVisiblePages; ++i) {
+ let page = visiblePages[i];
+ if (page.percent < 100) {
+ break;
+ }
+ if (page.id === currentId) {
+ stillFullyVisible = true;
+ break;
+ }
+ }
+ if (!stillFullyVisible) {
+ currentId = visiblePages[0].id;
+ }
+ if (!this.isInPresentationMode) {
+ this._setCurrentPageNumber(currentId);
+ }
+ this._updateLocation(visible.first);
+ this.eventBus.dispatch('updateviewarea', {
+ source: this,
+ location: this._location
+ });
+ }
+}
+exports.PDFViewer = PDFViewer;
+
+/***/ }),
+/* 22 */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.BaseViewer = undefined;
+
+var _pdfjsLib = __webpack_require__(1);
+
+var _ui_utils = __webpack_require__(0);
+
+var _pdf_rendering_queue = __webpack_require__(3);
+
+var _annotation_layer_builder = __webpack_require__(23);
var _dom_events = __webpack_require__(2);
-var _pdf_page_view = __webpack_require__(13);
+var _pdf_page_view = __webpack_require__(24);
var _pdf_link_service = __webpack_require__(5);
-var _text_layer_builder = __webpack_require__(14);
-
-const PresentationModeState = {
- UNKNOWN: 0,
- NORMAL: 1,
- CHANGING: 2,
- FULLSCREEN: 3
-};
+var _text_layer_builder = __webpack_require__(25);
+
const DEFAULT_CACHE_SIZE = 10;
function PDFPageViewBuffer(size) {
let data = [];
- this.push = function cachePush(view) {
+ this.push = function (view) {
let i = data.indexOf(view);
if (i >= 0) {
data.splice(i, 1);
}
data.push(view);
if (data.length > size) {
data.shift().destroy();
}
@@ -3809,18 +5794,22 @@ function isSameScale(oldScale, newScale)
if (Math.abs(newScale - oldScale) < 1e-15) {
return true;
}
return false;
}
function isPortraitOrientation(size) {
return size.width <= size.height;
}
-class PDFViewer {
+class BaseViewer {
constructor(options) {
+ if (this.constructor === BaseViewer) {
+ throw new Error('Cannot initialize BaseViewer.');
+ }
+ this._name = this.constructor.name;
this.container = options.container;
this.viewer = options.viewer || options.container.firstElementChild;
this.eventBus = options.eventBus || (0, _dom_events.getGlobalEventBus)();
this.linkService = options.linkService || new _pdf_link_service.SimpleLinkService();
this.downloadManager = options.downloadManager || null;
this.removePageBorders = options.removePageBorders || false;
this.enhanceTextSelection = options.enhanceTextSelection || false;
this.renderInteractiveForms = options.renderInteractiveForms || false;
@@ -3830,17 +5819,17 @@ class PDFViewer {
this.defaultRenderingQueue = !options.renderingQueue;
if (this.defaultRenderingQueue) {
this.renderingQueue = new _pdf_rendering_queue.PDFRenderingQueue();
this.renderingQueue.setViewer(this);
} else {
this.renderingQueue = options.renderingQueue;
}
this.scroll = (0, _ui_utils.watchScroll)(this.container, this._scrollUpdate.bind(this));
- this.presentationModeState = PresentationModeState.UNKNOWN;
+ this.presentationModeState = _ui_utils.PresentationModeState.UNKNOWN;
this._resetView();
if (this.removePageBorders) {
this.viewer.classList.add('removePageBorders');
}
}
get pagesCount() {
return this._pages.length;
}
@@ -3865,17 +5854,17 @@ class PDFViewer {
_setCurrentPageNumber(val, resetCurrentPageView = false) {
if (this._currentPageNumber === val) {
if (resetCurrentPageView) {
this._resetCurrentPageView();
}
return;
}
if (!(0 < val && val <= this.pagesCount)) {
- console.error(`PDFViewer._setCurrentPageNumber: "${val}" is out of bounds.`);
+ console.error(`${this._name}._setCurrentPageNumber: "${val}" is out of bounds.`);
return;
}
let arg = {
source: this,
pageNumber: val,
pageLabel: this._pageLabels && this._pageLabels[val - 1]
};
this._currentPageNumber = val;
@@ -3945,16 +5934,19 @@ class PDFViewer {
source: this,
pagesRotation: rotation,
pageNumber
});
if (this.defaultRenderingQueue) {
this.update();
}
}
+ get _setDocumentViewerElement() {
+ throw new Error('Not implemented: _setDocumentViewerElement');
+ }
setDocument(pdfDocument) {
if (this.pdfDocument) {
this._cancelRendering();
this._resetView();
}
this.pdfDocument = pdfDocument;
if (!pdfDocument) {
return;
@@ -3989,17 +5981,17 @@ class PDFViewer {
let scale = this.currentScale;
let viewport = pdfPage.getViewport(scale * _ui_utils.CSS_UNITS);
for (let pageNum = 1; pageNum <= pagesCount; ++pageNum) {
let textLayerFactory = null;
if (!_pdfjsLib.PDFJS.disableTextLayer) {
textLayerFactory = this;
}
let pageView = new _pdf_page_view.PDFPageView({
- container: this.viewer,
+ container: this._setDocumentViewerElement,
eventBus: this.eventBus,
id: pageNum,
scale,
defaultViewport: viewport.clone(),
renderingQueue: this.renderingQueue,
textLayerFactory,
annotationLayerFactory: this,
enhanceTextSelection: this.enhanceTextSelection,
@@ -4048,17 +6040,17 @@ class PDFViewer {
setPageLabels(labels) {
if (!this.pdfDocument) {
return;
}
if (!labels) {
this._pageLabels = null;
} else if (!(labels instanceof Array && this.pdfDocument.numPages === labels.length)) {
this._pageLabels = null;
- console.error('PDFViewer.setPageLabels: Invalid page labels.');
+ console.error(`${this._name}.setPageLabels: Invalid page labels.`);
} else {
this._pageLabels = labels;
}
for (let i = 0, ii = this._pages.length; i < ii; i++) {
let pageView = this._pages[i];
let label = this._pageLabels && this._pageLabels[i];
pageView.setPageLabel(label);
}
@@ -4077,16 +6069,19 @@ class PDFViewer {
this.viewer.textContent = '';
}
_scrollUpdate() {
if (this.pagesCount === 0) {
return;
}
this.update();
}
+ _scrollIntoView({ pageDiv, pageSpot = null, pageNumber = null }) {
+ throw new Error('Not implemented: _scrollIntoView');
+ }
_setScaleDispatchEvent(newScale, newValue, preset = false) {
let arg = {
source: this,
scale: newScale,
presetValue: preset ? newValue : undefined
};
this.eventBus.dispatch('scalechanging', arg);
this.eventBus.dispatch('scalechange', arg);
@@ -4148,43 +6143,43 @@ class PDFViewer {
scale = Math.min(pageWidthScale, pageHeightScale);
break;
case 'auto':
let isLandscape = currentPage.width > currentPage.height;
let horizontalScale = isLandscape ? Math.min(pageHeightScale, pageWidthScale) : pageWidthScale;
scale = Math.min(_ui_utils.MAX_AUTO_SCALE, horizontalScale);
break;
default:
- console.error(`PDFViewer._setScale: "${value}" is an unknown zoom value.`);
+ console.error(`${this._name}._setScale: "${value}" is an unknown zoom value.`);
return;
}
this._setScaleUpdatePages(scale, value, noScroll, true);
}
}
_resetCurrentPageView() {
if (this.isInPresentationMode) {
this._setScale(this._currentScaleValue, true);
}
let pageView = this._pages[this._currentPageNumber - 1];
- (0, _ui_utils.scrollIntoView)(pageView.div);
+ this._scrollIntoView({ pageDiv: pageView.div });
}
scrollPageIntoView(params) {
if (!this.pdfDocument) {
return;
}
let pageNumber = params.pageNumber || 0;
let dest = params.destArray || null;
let allowNegativeOffset = params.allowNegativeOffset || false;
if (this.isInPresentationMode || !dest) {
this._setCurrentPageNumber(pageNumber, true);
return;
}
let pageView = this._pages[pageNumber - 1];
if (!pageView) {
- console.error('PDFViewer.scrollPageIntoView: Invalid "pageNumber" parameter.');
+ console.error(`${this._name}.scrollPageIntoView: Invalid "pageNumber" parameter.`);
return;
}
let x = 0,
y = 0;
let width = 0,
height = 0,
widthScale,
heightScale;
@@ -4227,39 +6222,50 @@ class PDFViewer {
height = dest[5] - y;
let hPadding = this.removePageBorders ? 0 : _ui_utils.SCROLLBAR_PADDING;
let vPadding = this.removePageBorders ? 0 : _ui_utils.VERTICAL_PADDING;
widthScale = (this.container.clientWidth - hPadding) / width / _ui_utils.CSS_UNITS;
heightScale = (this.container.clientHeight - vPadding) / height / _ui_utils.CSS_UNITS;
scale = Math.min(Math.abs(widthScale), Math.abs(heightScale));
break;
default:
- console.error(`PDFViewer.scrollPageIntoView: "${dest[1].name}" ` + 'is not a valid destination type.');
+ console.error(`${this._name}.scrollPageIntoView: "${dest[1].name}" ` + 'is not a valid destination type.');
return;
}
if (scale && scale !== this._currentScale) {
this.currentScaleValue = scale;
} else if (this._currentScale === _ui_utils.UNKNOWN_SCALE) {
this.currentScaleValue = _ui_utils.DEFAULT_SCALE_VALUE;
}
if (scale === 'page-fit' && !dest[4]) {
- (0, _ui_utils.scrollIntoView)(pageView.div);
+ this._scrollIntoView({
+ pageDiv: pageView.div,
+ pageNumber
+ });
return;
}
let boundingRect = [pageView.viewport.convertToViewportPoint(x, y), pageView.viewport.convertToViewportPoint(x + width, y + height)];
let left = Math.min(boundingRect[0][0], boundingRect[1][0]);
let top = Math.min(boundingRect[0][1], boundingRect[1][1]);
if (!allowNegativeOffset) {
left = Math.max(left, 0);
top = Math.max(top, 0);
}
- (0, _ui_utils.scrollIntoView)(pageView.div, {
- left,
- top
- });
+ this._scrollIntoView({
+ pageDiv: pageView.div,
+ pageSpot: {
+ left,
+ top
+ },
+ pageNumber
+ });
+ }
+ _resizeBuffer(numVisiblePages) {
+ let suggestedCacheSize = Math.max(DEFAULT_CACHE_SIZE, 2 * numVisiblePages + 1);
+ this._buffer.resize(suggestedCacheSize);
}
_updateLocation(firstPage) {
let currentScale = this._currentScale;
let currentScaleValue = this._currentScaleValue;
let normalizedScaleValue = parseFloat(currentScaleValue) === currentScale ? Math.round(currentScale * 10000) / 100 : currentScaleValue;
let pageNumber = firstPage.id;
let pdfOpenParams = '#page=' + pageNumber;
pdfOpenParams += '&zoom=' + normalizedScaleValue;
@@ -4274,79 +6280,35 @@ class PDFViewer {
scale: normalizedScaleValue,
top: intTop,
left: intLeft,
rotation: this._pagesRotation,
pdfOpenParams
};
}
update() {
- let visible = this._getVisiblePages();
- let visiblePages = visible.views;
- if (visiblePages.length === 0) {
- return;
- }
- let suggestedCacheSize = Math.max(DEFAULT_CACHE_SIZE, 2 * visiblePages.length + 1);
- this._buffer.resize(suggestedCacheSize);
- this.renderingQueue.renderHighestPriority(visible);
- let currentId = this._currentPageNumber;
- let firstPage = visible.first;
- let stillFullyVisible = false;
- for (let i = 0, ii = visiblePages.length; i < ii; ++i) {
- let page = visiblePages[i];
- if (page.percent < 100) {
- break;
- }
- if (page.id === currentId) {
- stillFullyVisible = true;
- break;
- }
- }
- if (!stillFullyVisible) {
- currentId = visiblePages[0].id;
- }
- if (!this.isInPresentationMode) {
- this._setCurrentPageNumber(currentId);
- }
- this._updateLocation(firstPage);
- this.eventBus.dispatch('updateviewarea', {
- source: this,
- location: this._location
- });
+ throw new Error('Not implemented: update');
}
containsElement(element) {
return this.container.contains(element);
}
focus() {
this.container.focus();
}
get isInPresentationMode() {
- return this.presentationModeState === PresentationModeState.FULLSCREEN;
+ return this.presentationModeState === _ui_utils.PresentationModeState.FULLSCREEN;
}
get isChangingPresentationMode() {
- return this.presentationModeState === PresentationModeState.CHANGING;
+ return this.presentationModeState === _ui_utils.PresentationModeState.CHANGING;
}
get isHorizontalScrollbarEnabled() {
return this.isInPresentationMode ? false : this.container.scrollWidth > this.container.clientWidth;
}
_getVisiblePages() {
- if (!this.isInPresentationMode) {
- return (0, _ui_utils.getVisibleElements)(this.container, this._pages, true);
- }
- let visible = [];
- let currentPage = this._pages[this._currentPageNumber - 1];
- visible.push({
- id: currentPage.id,
- view: currentPage
- });
- return {
- first: currentPage,
- last: currentPage,
- views: visible
- };
+ throw new Error('Not implemented: _getVisiblePages');
}
cleanup() {
for (let i = 0, ii = this._pages.length; i < ii; i++) {
if (this._pages[i] && this._pages[i].renderingState !== _pdf_rendering_queue.RenderingStates.FINISHED) {
this._pages[i].reset();
}
}
}
@@ -4447,21 +6409,20 @@ class PDFViewer {
return {
width: size.height,
height: size.width,
rotation: (size.rotation + 90) % 360
};
});
}
}
-exports.PresentationModeState = PresentationModeState;
-exports.PDFViewer = PDFViewer;
+exports.BaseViewer = BaseViewer;
/***/ }),
-/* 12 */
+/* 23 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
@@ -4526,17 +6487,17 @@ class DefaultAnnotationLayerFactory {
l10n
});
}
}
exports.AnnotationLayerBuilder = AnnotationLayerBuilder;
exports.DefaultAnnotationLayerFactory = DefaultAnnotationLayerFactory;
/***/ }),
-/* 13 */
+/* 24 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
@@ -4970,17 +6931,17 @@ class PDFPageView {
} else {
this.div.removeAttribute('data-page-label');
}
}
}
exports.PDFPageView = PDFPageView;
/***/ }),
-/* 14 */
+/* 25 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
@@ -5239,1925 +7200,17 @@ class DefaultTextLayerFactory {
enhanceTextSelection
});
}
}
exports.TextLayerBuilder = TextLayerBuilder;
exports.DefaultTextLayerFactory = DefaultTextLayerFactory;
/***/ }),
-/* 15 */
-/***/ (function(module, exports, __webpack_require__) {
-
-"use strict";
-
-
-Object.defineProperty(exports, "__esModule", {
- value: true
-});
-class OverlayManager {
- constructor() {
- this._overlays = {};
- this._active = null;
- this._keyDownBound = this._keyDown.bind(this);
- }
- get active() {
- return this._active;
- }
- register(name, element, callerCloseMethod = null, canForceClose = false) {
- return new Promise(resolve => {
- let container;
- if (!name || !element || !(container = element.parentNode)) {
- throw new Error('Not enough parameters.');
- } else if (this._overlays[name]) {
- throw new Error('The overlay is already registered.');
- }
- this._overlays[name] = {
- element,
- container,
- callerCloseMethod,
- canForceClose
- };
- resolve();
- });
- }
- unregister(name) {
- return new Promise(resolve => {
- if (!this._overlays[name]) {
- throw new Error('The overlay does not exist.');
- } else if (this._active === name) {
- throw new Error('The overlay cannot be removed while it is active.');
- }
- delete this._overlays[name];
- resolve();
- });
- }
- open(name) {
- return new Promise(resolve => {
- if (!this._overlays[name]) {
- throw new Error('The overlay does not exist.');
- } else if (this._active) {
- if (this._overlays[name].canForceClose) {
- this._closeThroughCaller();
- } else if (this._active === name) {
- throw new Error('The overlay is already active.');
- } else {
- throw new Error('Another overlay is currently active.');
- }
- }
- this._active = name;
- this._overlays[this._active].element.classList.remove('hidden');
- this._overlays[this._active].container.classList.remove('hidden');
- window.addEventListener('keydown', this._keyDownBound);
- resolve();
- });
- }
- close(name) {
- return new Promise(resolve => {
- if (!this._overlays[name]) {
- throw new Error('The overlay does not exist.');
- } else if (!this._active) {
- throw new Error('The overlay is currently not active.');
- } else if (this._active !== name) {
- throw new Error('Another overlay is currently active.');
- }
- this._overlays[this._active].container.classList.add('hidden');
- this._overlays[this._active].element.classList.add('hidden');
- this._active = null;
- window.removeEventListener('keydown', this._keyDownBound);
- resolve();
- });
- }
- _keyDown(evt) {
- if (this._active && evt.keyCode === 27) {
- this._closeThroughCaller();
- evt.preventDefault();
- }
- }
- _closeThroughCaller() {
- if (this._overlays[this._active].callerCloseMethod) {
- this._overlays[this._active].callerCloseMethod();
- }
- if (this._active) {
- this.close(this._active);
- }
- }
-}
-exports.OverlayManager = OverlayManager;
-
-/***/ }),
-/* 16 */
-/***/ (function(module, exports, __webpack_require__) {
-
-"use strict";
-
-
-Object.defineProperty(exports, "__esModule", {
- value: true
-});
-exports.PasswordPrompt = undefined;
-
-var _ui_utils = __webpack_require__(0);
-
-var _pdfjsLib = __webpack_require__(1);
-
-class PasswordPrompt {
- constructor(options, overlayManager, l10n = _ui_utils.NullL10n) {
- this.overlayName = options.overlayName;
- this.container = options.container;
- this.label = options.label;
- this.input = options.input;
- this.submitButton = options.submitButton;
- this.cancelButton = options.cancelButton;
- this.overlayManager = overlayManager;
- this.l10n = l10n;
- this.updateCallback = null;
- this.reason = null;
- this.submitButton.addEventListener('click', this.verify.bind(this));
- this.cancelButton.addEventListener('click', this.close.bind(this));
- this.input.addEventListener('keydown', e => {
- if (e.keyCode === 13) {
- this.verify();
- }
- });
- this.overlayManager.register(this.overlayName, this.container, this.close.bind(this), true);
- }
- open() {
- this.overlayManager.open(this.overlayName).then(() => {
- this.input.focus();
- let promptString;
- if (this.reason === _pdfjsLib.PasswordResponses.INCORRECT_PASSWORD) {
- promptString = this.l10n.get('password_invalid', null, 'Invalid password. Please try again.');
- } else {
- promptString = this.l10n.get('password_label', null, 'Enter the password to open this PDF file.');
- }
- promptString.then(msg => {
- this.label.textContent = msg;
- });
- });
- }
- close() {
- this.overlayManager.close(this.overlayName).then(() => {
- this.input.value = '';
- });
- }
- verify() {
- let password = this.input.value;
- if (password && password.length > 0) {
- this.close();
- return this.updateCallback(password);
- }
- }
- setUpdateCallback(updateCallback, reason) {
- this.updateCallback = updateCallback;
- this.reason = reason;
- }
-}
-exports.PasswordPrompt = PasswordPrompt;
-
-/***/ }),
-/* 17 */
-/***/ (function(module, exports, __webpack_require__) {
-
-"use strict";
-
-
-Object.defineProperty(exports, "__esModule", {
- value: true
-});
-exports.PDFAttachmentViewer = undefined;
-
-var _pdfjsLib = __webpack_require__(1);
-
-class PDFAttachmentViewer {
- constructor({ container, eventBus, downloadManager }) {
- this.container = container;
- this.eventBus = eventBus;
- this.downloadManager = downloadManager;
- this.reset();
- this.eventBus.on('fileattachmentannotation', this._appendAttachment.bind(this));
- }
- reset(keepRenderedCapability = false) {
- this.attachments = null;
- this.container.textContent = '';
- if (!keepRenderedCapability) {
- this._renderedCapability = (0, _pdfjsLib.createPromiseCapability)();
- }
- }
- _dispatchEvent(attachmentsCount) {
- this._renderedCapability.resolve();
- this.eventBus.dispatch('attachmentsloaded', {
- source: this,
- attachmentsCount
- });
- }
- _bindPdfLink(button, content, filename) {
- if (_pdfjsLib.PDFJS.disableCreateObjectURL) {
- throw new Error('bindPdfLink: ' + 'Unsupported "PDFJS.disableCreateObjectURL" value.');
- }
- let blobUrl;
- button.onclick = function () {
- if (!blobUrl) {
- blobUrl = (0, _pdfjsLib.createObjectURL)(content, 'application/pdf');
- }
- let viewerUrl;
- viewerUrl = blobUrl + '?' + encodeURIComponent(filename);
- window.open(viewerUrl);
- return false;
- };
- }
- _bindLink(button, content, filename) {
- button.onclick = () => {
- this.downloadManager.downloadData(content, filename, '');
- return false;
- };
- }
- render({ attachments, keepRenderedCapability = false }) {
- let attachmentsCount = 0;
- if (this.attachments) {
- this.reset(keepRenderedCapability === true);
- }
- this.attachments = attachments || null;
- if (!attachments) {
- this._dispatchEvent(attachmentsCount);
- return;
- }
- let names = Object.keys(attachments).sort(function (a, b) {
- return a.toLowerCase().localeCompare(b.toLowerCase());
- });
- attachmentsCount = names.length;
- for (let i = 0; i < attachmentsCount; i++) {
- let item = attachments[names[i]];
- let filename = (0, _pdfjsLib.removeNullCharacters)((0, _pdfjsLib.getFilenameFromUrl)(item.filename));
- let div = document.createElement('div');
- div.className = 'attachmentsItem';
- let button = document.createElement('button');
- button.textContent = filename;
- if (/\.pdf$/i.test(filename) && !_pdfjsLib.PDFJS.disableCreateObjectURL) {
- this._bindPdfLink(button, item.content, filename);
- } else {
- this._bindLink(button, item.content, filename);
- }
- div.appendChild(button);
- this.container.appendChild(div);
- }
- this._dispatchEvent(attachmentsCount);
- }
- _appendAttachment({ id, filename, content }) {
- this._renderedCapability.promise.then(() => {
- let attachments = this.attachments;
- if (!attachments) {
- attachments = Object.create(null);
- } else {
- for (let name in attachments) {
- if (id === name) {
- return;
- }
- }
- }
- attachments[id] = {
- filename,
- content
- };
- this.render({
- attachments,
- keepRenderedCapability: true
- });
- });
- }
-}
-exports.PDFAttachmentViewer = PDFAttachmentViewer;
-
-/***/ }),
-/* 18 */
-/***/ (function(module, exports, __webpack_require__) {
-
-"use strict";
-
-
-Object.defineProperty(exports, "__esModule", {
- value: true
-});
-exports.PDFDocumentProperties = undefined;
-
-var _ui_utils = __webpack_require__(0);
-
-var _pdfjsLib = __webpack_require__(1);
-
-const DEFAULT_FIELD_CONTENT = '-';
-class PDFDocumentProperties {
- constructor({ overlayName, fields, container, closeButton }, overlayManager, l10n = _ui_utils.NullL10n) {
- this.overlayName = overlayName;
- this.fields = fields;
- this.container = container;
- this.overlayManager = overlayManager;
- this.l10n = l10n;
- this._reset();
- if (closeButton) {
- closeButton.addEventListener('click', this.close.bind(this));
- }
- this.overlayManager.register(this.overlayName, this.container, this.close.bind(this));
- }
- open() {
- let freezeFieldData = data => {
- Object.defineProperty(this, 'fieldData', {
- value: Object.freeze(data),
- writable: false,
- enumerable: true,
- configurable: true
- });
- };
- Promise.all([this.overlayManager.open(this.overlayName), this._dataAvailableCapability.promise]).then(() => {
- if (this.fieldData) {
- this._updateUI();
- return;
- }
- this.pdfDocument.getMetadata().then(({ info, metadata }) => {
- return Promise.all([info, metadata, this._parseFileSize(this.maybeFileSize), this._parseDate(info.CreationDate), this._parseDate(info.ModDate)]);
- }).then(([info, metadata, fileSize, creationDate, modificationDate]) => {
- freezeFieldData({
- 'fileName': (0, _ui_utils.getPDFFileNameFromURL)(this.url),
- 'fileSize': fileSize,
- 'title': info.Title,
- 'author': info.Author,
- 'subject': info.Subject,
- 'keywords': info.Keywords,
- 'creationDate': creationDate,
- 'modificationDate': modificationDate,
- 'creator': info.Creator,
- 'producer': info.Producer,
- 'version': info.PDFFormatVersion,
- 'pageCount': this.pdfDocument.numPages
- });
- this._updateUI();
- return this.pdfDocument.getDownloadInfo();
- }).then(({ length }) => {
- return this._parseFileSize(length);
- }).then(fileSize => {
- let data = (0, _ui_utils.cloneObj)(this.fieldData);
- data['fileSize'] = fileSize;
- freezeFieldData(data);
- this._updateUI();
- });
- });
- }
- close() {
- this.overlayManager.close(this.overlayName);
- }
- setDocument(pdfDocument, url) {
- if (this.pdfDocument) {
- this._reset();
- this._updateUI(true);
- }
- if (!pdfDocument) {
- return;
- }
- this.pdfDocument = pdfDocument;
- this.url = url;
- this._dataAvailableCapability.resolve();
- }
- setFileSize(fileSize) {
- if (typeof fileSize === 'number' && fileSize > 0) {
- this.maybeFileSize = fileSize;
- }
- }
- _reset() {
- this.pdfDocument = null;
- this.url = null;
- this.maybeFileSize = 0;
- delete this.fieldData;
- this._dataAvailableCapability = (0, _pdfjsLib.createPromiseCapability)();
- }
- _updateUI(reset = false) {
- if (reset || !this.fieldData) {
- for (let id in this.fields) {
- this.fields[id].textContent = DEFAULT_FIELD_CONTENT;
- }
- return;
- }
- if (this.overlayManager.active !== this.overlayName) {
- return;
- }
- for (let id in this.fields) {
- let content = this.fieldData[id];
- this.fields[id].textContent = content || content === 0 ? content : DEFAULT_FIELD_CONTENT;
- }
- }
- _parseFileSize(fileSize = 0) {
- let kb = fileSize / 1024;
- if (!kb) {
- return Promise.resolve(undefined);
- } else if (kb < 1024) {
- return this.l10n.get('document_properties_kb', {
- size_kb: (+kb.toPrecision(3)).toLocaleString(),
- size_b: fileSize.toLocaleString()
- }, '{{size_kb}} KB ({{size_b}} bytes)');
- }
- return this.l10n.get('document_properties_mb', {
- size_mb: (+(kb / 1024).toPrecision(3)).toLocaleString(),
- size_b: fileSize.toLocaleString()
- }, '{{size_mb}} MB ({{size_b}} bytes)');
- }
- _parseDate(inputDate) {
- if (!inputDate) {
- return;
- }
- let dateToParse = inputDate;
- if (dateToParse.substring(0, 2) === 'D:') {
- dateToParse = dateToParse.substring(2);
- }
- let year = parseInt(dateToParse.substring(0, 4), 10);
- let month = parseInt(dateToParse.substring(4, 6), 10) - 1;
- let day = parseInt(dateToParse.substring(6, 8), 10);
- let hours = parseInt(dateToParse.substring(8, 10), 10);
- let minutes = parseInt(dateToParse.substring(10, 12), 10);
- let seconds = parseInt(dateToParse.substring(12, 14), 10);
- let utRel = dateToParse.substring(14, 15);
- let offsetHours = parseInt(dateToParse.substring(15, 17), 10);
- let offsetMinutes = parseInt(dateToParse.substring(18, 20), 10);
- if (utRel === '-') {
- hours += offsetHours;
- minutes += offsetMinutes;
- } else if (utRel === '+') {
- hours -= offsetHours;
- minutes -= offsetMinutes;
- }
- let date = new Date(Date.UTC(year, month, day, hours, minutes, seconds));
- let dateString = date.toLocaleDateString();
- let timeString = date.toLocaleTimeString();
- return this.l10n.get('document_properties_date_string', {
- date: dateString,
- time: timeString
- }, '{{date}}, {{time}}');
- }
-}
-exports.PDFDocumentProperties = PDFDocumentProperties;
-
-/***/ }),
-/* 19 */
-/***/ (function(module, exports, __webpack_require__) {
-
-"use strict";
-
-
-Object.defineProperty(exports, "__esModule", {
- value: true
-});
-exports.PDFFindBar = undefined;
-
-var _pdf_find_controller = __webpack_require__(7);
-
-var _ui_utils = __webpack_require__(0);
-
-class PDFFindBar {
- constructor(options, l10n = _ui_utils.NullL10n) {
- this.opened = false;
- this.bar = options.bar || null;
- this.toggleButton = options.toggleButton || null;
- this.findField = options.findField || null;
- this.highlightAll = options.highlightAllCheckbox || null;
- this.caseSensitive = options.caseSensitiveCheckbox || null;
- this.findMsg = options.findMsg || null;
- this.findResultsCount = options.findResultsCount || null;
- this.findStatusIcon = options.findStatusIcon || null;
- this.findPreviousButton = options.findPreviousButton || null;
- this.findNextButton = options.findNextButton || null;
- this.findController = options.findController || null;
- this.eventBus = options.eventBus;
- this.l10n = l10n;
- if (this.findController === null) {
- throw new Error('PDFFindBar cannot be used without a ' + 'PDFFindController instance.');
- }
- this.toggleButton.addEventListener('click', () => {
- this.toggle();
- });
- this.findField.addEventListener('input', () => {
- this.dispatchEvent('');
- });
- this.bar.addEventListener('keydown', e => {
- switch (e.keyCode) {
- case 13:
- if (e.target === this.findField) {
- this.dispatchEvent('again', e.shiftKey);
- }
- break;
- case 27:
- this.close();
- break;
- }
- });
- this.findPreviousButton.addEventListener('click', () => {
- this.dispatchEvent('again', true);
- });
- this.findNextButton.addEventListener('click', () => {
- this.dispatchEvent('again', false);
- });
- this.highlightAll.addEventListener('click', () => {
- this.dispatchEvent('highlightallchange');
- });
- this.caseSensitive.addEventListener('click', () => {
- this.dispatchEvent('casesensitivitychange');
- });
- this.eventBus.on('resize', this._adjustWidth.bind(this));
- }
- reset() {
- this.updateUIState();
- }
- dispatchEvent(type, findPrev) {
- this.eventBus.dispatch('find', {
- source: this,
- type,
- query: this.findField.value,
- caseSensitive: this.caseSensitive.checked,
- phraseSearch: true,
- highlightAll: this.highlightAll.checked,
- findPrevious: findPrev
- });
- }
- updateUIState(state, previous, matchCount) {
- let notFound = false;
- let findMsg = '';
- let status = '';
- switch (state) {
- case _pdf_find_controller.FindState.FOUND:
- break;
- case _pdf_find_controller.FindState.PENDING:
- status = 'pending';
- break;
- case _pdf_find_controller.FindState.NOT_FOUND:
- findMsg = this.l10n.get('find_not_found', null, 'Phrase not found');
- notFound = true;
- break;
- case _pdf_find_controller.FindState.WRAPPED:
- if (previous) {
- findMsg = this.l10n.get('find_reached_top', null, 'Reached top of document, continued from bottom');
- } else {
- findMsg = this.l10n.get('find_reached_bottom', null, 'Reached end of document, continued from top');
- }
- break;
- }
- if (notFound) {
- this.findField.classList.add('notFound');
- } else {
- this.findField.classList.remove('notFound');
- }
- this.findField.setAttribute('data-status', status);
- Promise.resolve(findMsg).then(msg => {
- this.findMsg.textContent = msg;
- this._adjustWidth();
- });
- this.updateResultsCount(matchCount);
- }
- updateResultsCount(matchCount) {
- if (!this.findResultsCount) {
- return;
- }
- if (!matchCount) {
- this.findResultsCount.classList.add('hidden');
- this.findResultsCount.textContent = '';
- } else {
- this.findResultsCount.textContent = matchCount.toLocaleString();
- this.findResultsCount.classList.remove('hidden');
- }
- this._adjustWidth();
- }
- open() {
- if (!this.opened) {
- this.opened = true;
- this.toggleButton.classList.add('toggled');
- this.bar.classList.remove('hidden');
- }
- this.findField.select();
- this.findField.focus();
- this._adjustWidth();
- }
- close() {
- if (!this.opened) {
- return;
- }
- this.opened = false;
- this.toggleButton.classList.remove('toggled');
- this.bar.classList.add('hidden');
- this.findController.active = false;
- }
- toggle() {
- if (this.opened) {
- this.close();
- } else {
- this.open();
- }
- }
- _adjustWidth() {
- if (!this.opened) {
- return;
- }
- this.bar.classList.remove('wrapContainers');
- let findbarHeight = this.bar.clientHeight;
- let inputContainerHeight = this.bar.firstElementChild.clientHeight;
- if (findbarHeight > inputContainerHeight) {
- this.bar.classList.add('wrapContainers');
- }
- }
-}
-exports.PDFFindBar = PDFFindBar;
-
-/***/ }),
-/* 20 */
-/***/ (function(module, exports, __webpack_require__) {
-
-"use strict";
-
-
-Object.defineProperty(exports, "__esModule", {
- value: true
-});
-exports.isDestsEqual = exports.PDFHistory = undefined;
-
-var _ui_utils = __webpack_require__(0);
-
-var _dom_events = __webpack_require__(2);
-
-const HASH_CHANGE_TIMEOUT = 1000;
-const POSITION_UPDATED_THRESHOLD = 50;
-const UPDATE_VIEWAREA_TIMEOUT = 1000;
-function getCurrentHash() {
- return document.location.hash;
-}
-function parseCurrentHash(linkService) {
- let hash = unescape(getCurrentHash()).substring(1);
- let params = (0, _ui_utils.parseQueryString)(hash);
- let page = params.page | 0;
- if (!(Number.isInteger(page) && page > 0 && page <= linkService.pagesCount)) {
- page = null;
- }
- return {
- hash,
- page,
- rotation: linkService.rotation
- };
-}
-class PDFHistory {
- constructor({ linkService, eventBus }) {
- this.linkService = linkService;
- this.eventBus = eventBus || (0, _dom_events.getGlobalEventBus)();
- this.initialized = false;
- this.initialBookmark = null;
- this.initialRotation = null;
- this._boundEvents = Object.create(null);
- this._isViewerInPresentationMode = false;
- this._isPagesLoaded = false;
- this.eventBus.on('presentationmodechanged', evt => {
- this._isViewerInPresentationMode = evt.active || evt.switchInProgress;
- });
- this.eventBus.on('pagesloaded', evt => {
- this._isPagesLoaded = !!evt.pagesCount;
- });
- }
- initialize(fingerprint, resetHistory = false) {
- if (!fingerprint || typeof fingerprint !== 'string') {
- console.error('PDFHistory.initialize: The "fingerprint" must be a non-empty string.');
- return;
- }
- let reInitialized = this.initialized && this.fingerprint !== fingerprint;
- this.fingerprint = fingerprint;
- if (!this.initialized) {
- this._bindEvents();
- }
- let state = window.history.state;
- this.initialized = true;
- this.initialBookmark = null;
- this.initialRotation = null;
- this._popStateInProgress = false;
- this._blockHashChange = 0;
- this._currentHash = getCurrentHash();
- this._numPositionUpdates = 0;
- this._currentUid = this._uid = 0;
- this._destination = null;
- this._position = null;
- if (!this._isValidState(state) || resetHistory) {
- let { hash, page, rotation } = parseCurrentHash(this.linkService);
- if (!hash || reInitialized || resetHistory) {
- this._pushOrReplaceState(null, true);
- return;
- }
- this._pushOrReplaceState({
- hash,
- page,
- rotation
- }, true);
- return;
- }
- let destination = state.destination;
- this._updateInternalState(destination, state.uid, true);
- if (destination.rotation !== undefined) {
- this.initialRotation = destination.rotation;
- }
- if (destination.dest) {
- this.initialBookmark = JSON.stringify(destination.dest);
- this._destination.page = null;
- } else if (destination.hash) {
- this.initialBookmark = destination.hash;
- } else if (destination.page) {
- this.initialBookmark = `page=${destination.page}`;
- }
- }
- push({ namedDest, explicitDest, pageNumber }) {
- if (!this.initialized) {
- return;
- }
- if (namedDest && typeof namedDest !== 'string' || !(explicitDest instanceof Array) || !(Number.isInteger(pageNumber) && pageNumber > 0 && pageNumber <= this.linkService.pagesCount)) {
- console.error('PDFHistory.push: Invalid parameters.');
- return;
- }
- let hash = namedDest || JSON.stringify(explicitDest);
- if (!hash) {
- return;
- }
- let forceReplace = false;
- if (this._destination && (this._destination.hash === hash || isDestsEqual(this._destination.dest, explicitDest))) {
- if (this._destination.page) {
- return;
- }
- forceReplace = true;
- }
- if (this._popStateInProgress && !forceReplace) {
- return;
- }
- this._pushOrReplaceState({
- dest: explicitDest,
- hash,
- page: pageNumber,
- rotation: this.linkService.rotation
- }, forceReplace);
- if (!this._popStateInProgress) {
- this._popStateInProgress = true;
- Promise.resolve().then(() => {
- this._popStateInProgress = false;
- });
- }
- }
- pushCurrentPosition() {
- if (!this.initialized || this._popStateInProgress) {
- return;
- }
- this._tryPushCurrentPosition();
- }
- back() {
- if (!this.initialized || this._popStateInProgress) {
- return;
- }
- let state = window.history.state;
- if (this._isValidState(state) && state.uid > 0) {
- window.history.back();
- }
- }
- forward() {
- if (!this.initialized || this._popStateInProgress) {
- return;
- }
- let state = window.history.state;
- if (this._isValidState(state) && state.uid < this._uid - 1) {
- window.history.forward();
- }
- }
- get popStateInProgress() {
- return this.initialized && (this._popStateInProgress || this._blockHashChange > 0);
- }
- _pushOrReplaceState(destination, forceReplace = false) {
- let shouldReplace = forceReplace || !this._destination;
- let newState = {
- fingerprint: this.fingerprint,
- uid: shouldReplace ? this._currentUid : this._uid,
- destination
- };
- this._updateInternalState(destination, newState.uid);
- if (shouldReplace) {
- window.history.replaceState(newState, '');
- } else {
- window.history.pushState(newState, '');
- }
- }
- _tryPushCurrentPosition(temporary = false) {
- if (!this._position) {
- return;
- }
- let position = this._position;
- if (temporary) {
- position = (0, _ui_utils.cloneObj)(this._position);
- position.temporary = true;
- }
- if (!this._destination) {
- this._pushOrReplaceState(position);
- return;
- }
- if (this._destination.temporary) {
- this._pushOrReplaceState(position, true);
- return;
- }
- if (this._destination.hash === position.hash) {
- return;
- }
- if (!this._destination.page && (POSITION_UPDATED_THRESHOLD <= 0 || this._numPositionUpdates <= POSITION_UPDATED_THRESHOLD)) {
- return;
- }
- let forceReplace = false;
- if (this._destination.page === position.first || this._destination.page === position.page) {
- if (this._destination.dest || !this._destination.first) {
- return;
- }
- forceReplace = true;
- }
- this._pushOrReplaceState(position, forceReplace);
- }
- _isValidState(state) {
- if (!state) {
- return false;
- }
- if (state.fingerprint !== this.fingerprint) {
- return false;
- }
- if (!Number.isInteger(state.uid) || state.uid < 0) {
- return false;
- }
- if (state.destination === null || typeof state.destination !== 'object') {
- return false;
- }
- return true;
- }
- _updateInternalState(destination, uid, removeTemporary = false) {
- if (this._updateViewareaTimeout) {
- clearTimeout(this._updateViewareaTimeout);
- this._updateViewareaTimeout = null;
- }
- if (removeTemporary && destination && destination.temporary) {
- delete destination.temporary;
- }
- this._destination = destination;
- this._currentUid = uid;
- this._uid = this._currentUid + 1;
- this._numPositionUpdates = 0;
- }
- _updateViewarea({ location }) {
- if (this._updateViewareaTimeout) {
- clearTimeout(this._updateViewareaTimeout);
- this._updateViewareaTimeout = null;
- }
- this._position = {
- hash: this._isViewerInPresentationMode ? `page=${location.pageNumber}` : location.pdfOpenParams.substring(1),
- page: this.linkService.page,
- first: location.pageNumber,
- rotation: location.rotation
- };
- if (this._popStateInProgress) {
- return;
- }
- if (POSITION_UPDATED_THRESHOLD > 0 && this._isPagesLoaded && this._destination && !this._destination.page) {
- this._numPositionUpdates++;
- }
- if (UPDATE_VIEWAREA_TIMEOUT > 0) {
- this._updateViewareaTimeout = setTimeout(() => {
- if (!this._popStateInProgress) {
- this._tryPushCurrentPosition(true);
- }
- this._updateViewareaTimeout = null;
- }, UPDATE_VIEWAREA_TIMEOUT);
- }
- }
- _popState({ state }) {
- let newHash = getCurrentHash(),
- hashChanged = this._currentHash !== newHash;
- this._currentHash = newHash;
- if (!state || false) {
- this._currentUid = this._uid;
- let { hash, page, rotation } = parseCurrentHash(this.linkService);
- this._pushOrReplaceState({
- hash,
- page,
- rotation
- }, true);
- return;
- }
- if (!this._isValidState(state)) {
- return;
- }
- this._popStateInProgress = true;
- if (hashChanged) {
- this._blockHashChange++;
- (0, _ui_utils.waitOnEventOrTimeout)({
- target: window,
- name: 'hashchange',
- delay: HASH_CHANGE_TIMEOUT
- }).then(() => {
- this._blockHashChange--;
- });
- }
- let destination = state.destination;
- this._updateInternalState(destination, state.uid, true);
- if ((0, _ui_utils.isValidRotation)(destination.rotation)) {
- this.linkService.rotation = destination.rotation;
- }
- if (destination.dest) {
- this.linkService.navigateTo(destination.dest);
- } else if (destination.hash) {
- this.linkService.setHash(destination.hash);
- } else if (destination.page) {
- this.linkService.page = destination.page;
- }
- Promise.resolve().then(() => {
- this._popStateInProgress = false;
- });
- }
- _bindEvents() {
- let { _boundEvents, eventBus } = this;
- _boundEvents.updateViewarea = this._updateViewarea.bind(this);
- _boundEvents.popState = this._popState.bind(this);
- _boundEvents.pageHide = evt => {
- if (!this._destination) {
- this._tryPushCurrentPosition();
- }
- };
- eventBus.on('updateviewarea', _boundEvents.updateViewarea);
- window.addEventListener('popstate', _boundEvents.popState);
- window.addEventListener('pagehide', _boundEvents.pageHide);
- }
-}
-function isDestsEqual(firstDest, secondDest) {
- function isEntryEqual(first, second) {
- if (typeof first !== typeof second) {
- return false;
- }
- if (first instanceof Array || second instanceof Array) {
- return false;
- }
- if (first !== null && typeof first === 'object' && second !== null) {
- if (Object.keys(first).length !== Object.keys(second).length) {
- return false;
- }
- for (var key in first) {
- if (!isEntryEqual(first[key], second[key])) {
- return false;
- }
- }
- return true;
- }
- return first === second || Number.isNaN(first) && Number.isNaN(second);
- }
- if (!(firstDest instanceof Array && secondDest instanceof Array)) {
- return false;
- }
- if (firstDest.length !== secondDest.length) {
- return false;
- }
- for (let i = 0, ii = firstDest.length; i < ii; i++) {
- if (!isEntryEqual(firstDest[i], secondDest[i])) {
- return false;
- }
- }
- return true;
-}
-exports.PDFHistory = PDFHistory;
-exports.isDestsEqual = isDestsEqual;
-
-/***/ }),
-/* 21 */
-/***/ (function(module, exports, __webpack_require__) {
-
-"use strict";
-
-
-Object.defineProperty(exports, "__esModule", {
- value: true
-});
-exports.PDFOutlineViewer = undefined;
-
-var _pdfjsLib = __webpack_require__(1);
-
-const DEFAULT_TITLE = '\u2013';
-class PDFOutlineViewer {
- constructor({ container, linkService, eventBus }) {
- this.container = container;
- this.linkService = linkService;
- this.eventBus = eventBus;
- this.reset();
- }
- reset() {
- this.outline = null;
- this.lastToggleIsShow = true;
- this.container.textContent = '';
- this.container.classList.remove('outlineWithDeepNesting');
- }
- _dispatchEvent(outlineCount) {
- this.eventBus.dispatch('outlineloaded', {
- source: this,
- outlineCount
- });
- }
- _bindLink(element, item) {
- if (item.url) {
- (0, _pdfjsLib.addLinkAttributes)(element, {
- url: item.url,
- target: item.newWindow ? _pdfjsLib.PDFJS.LinkTarget.BLANK : undefined
- });
- return;
- }
- let destination = item.dest;
- element.href = this.linkService.getDestinationHash(destination);
- element.onclick = () => {
- if (destination) {
- this.linkService.navigateTo(destination);
- }
- return false;
- };
- }
- _setStyles(element, item) {
- let styleStr = '';
- if (item.bold) {
- styleStr += 'font-weight: bold;';
- }
- if (item.italic) {
- styleStr += 'font-style: italic;';
- }
- if (styleStr) {
- element.setAttribute('style', styleStr);
- }
- }
- _addToggleButton(div) {
- let toggler = document.createElement('div');
- toggler.className = 'outlineItemToggler';
- toggler.onclick = evt => {
- evt.stopPropagation();
- toggler.classList.toggle('outlineItemsHidden');
- if (evt.shiftKey) {
- let shouldShowAll = !toggler.classList.contains('outlineItemsHidden');
- this._toggleOutlineItem(div, shouldShowAll);
- }
- };
- div.insertBefore(toggler, div.firstChild);
- }
- _toggleOutlineItem(root, show) {
- this.lastToggleIsShow = show;
- let togglers = root.querySelectorAll('.outlineItemToggler');
- for (let i = 0, ii = togglers.length; i < ii; ++i) {
- togglers[i].classList[show ? 'remove' : 'add']('outlineItemsHidden');
- }
- }
- toggleOutlineTree() {
- if (!this.outline) {
- return;
- }
- this._toggleOutlineItem(this.container, !this.lastToggleIsShow);
- }
- render({ outline }) {
- let outlineCount = 0;
- if (this.outline) {
- this.reset();
- }
- this.outline = outline || null;
- if (!outline) {
- this._dispatchEvent(outlineCount);
- return;
- }
- let fragment = document.createDocumentFragment();
- let queue = [{
- parent: fragment,
- items: this.outline
- }];
- let hasAnyNesting = false;
- while (queue.length > 0) {
- let levelData = queue.shift();
- for (let i = 0, len = levelData.items.length; i < len; i++) {
- let item = levelData.items[i];
- let div = document.createElement('div');
- div.className = 'outlineItem';
- let element = document.createElement('a');
- this._bindLink(element, item);
- this._setStyles(element, item);
- element.textContent = (0, _pdfjsLib.removeNullCharacters)(item.title) || DEFAULT_TITLE;
- div.appendChild(element);
- if (item.items.length > 0) {
- hasAnyNesting = true;
- this._addToggleButton(div);
- let itemsDiv = document.createElement('div');
- itemsDiv.className = 'outlineItems';
- div.appendChild(itemsDiv);
- queue.push({
- parent: itemsDiv,
- items: item.items
- });
- }
- levelData.parent.appendChild(div);
- outlineCount++;
- }
- }
- if (hasAnyNesting) {
- this.container.classList.add('outlineWithDeepNesting');
- }
- this.container.appendChild(fragment);
- this._dispatchEvent(outlineCount);
- }
-}
-exports.PDFOutlineViewer = PDFOutlineViewer;
-
-/***/ }),
-/* 22 */
-/***/ (function(module, exports, __webpack_require__) {
-
-"use strict";
-
-
-Object.defineProperty(exports, "__esModule", {
- value: true
-});
-exports.PDFPresentationMode = undefined;
-
-var _ui_utils = __webpack_require__(0);
-
-const DELAY_BEFORE_RESETTING_SWITCH_IN_PROGRESS = 1500;
-const DELAY_BEFORE_HIDING_CONTROLS = 3000;
-const ACTIVE_SELECTOR = 'pdfPresentationMode';
-const CONTROLS_SELECTOR = 'pdfPresentationModeControls';
-const MOUSE_SCROLL_COOLDOWN_TIME = 50;
-const PAGE_SWITCH_THRESHOLD = 0.1;
-const SWIPE_MIN_DISTANCE_THRESHOLD = 50;
-const SWIPE_ANGLE_THRESHOLD = Math.PI / 6;
-class PDFPresentationMode {
- constructor({ container, viewer = null, pdfViewer, eventBus, contextMenuItems = null }) {
- this.container = container;
- this.viewer = viewer || container.firstElementChild;
- this.pdfViewer = pdfViewer;
- this.eventBus = eventBus;
- this.active = false;
- this.args = null;
- this.contextMenuOpen = false;
- this.mouseScrollTimeStamp = 0;
- this.mouseScrollDelta = 0;
- this.touchSwipeState = null;
- if (contextMenuItems) {
- contextMenuItems.contextFirstPage.addEventListener('click', () => {
- this.contextMenuOpen = false;
- this.eventBus.dispatch('firstpage');
- });
- contextMenuItems.contextLastPage.addEventListener('click', () => {
- this.contextMenuOpen = false;
- this.eventBus.dispatch('lastpage');
- });
- contextMenuItems.contextPageRotateCw.addEventListener('click', () => {
- this.contextMenuOpen = false;
- this.eventBus.dispatch('rotatecw');
- });
- contextMenuItems.contextPageRotateCcw.addEventListener('click', () => {
- this.contextMenuOpen = false;
- this.eventBus.dispatch('rotateccw');
- });
- }
- }
- request() {
- if (this.switchInProgress || this.active || !this.viewer.hasChildNodes()) {
- return false;
- }
- this._addFullscreenChangeListeners();
- this._setSwitchInProgress();
- this._notifyStateChange();
- if (this.container.requestFullscreen) {
- this.container.requestFullscreen();
- } else if (this.container.mozRequestFullScreen) {
- this.container.mozRequestFullScreen();
- } else if (this.container.webkitRequestFullscreen) {
- this.container.webkitRequestFullscreen(Element.ALLOW_KEYBOARD_INPUT);
- } else if (this.container.msRequestFullscreen) {
- this.container.msRequestFullscreen();
- } else {
- return false;
- }
- this.args = {
- page: this.pdfViewer.currentPageNumber,
- previousScale: this.pdfViewer.currentScaleValue
- };
- return true;
- }
- _mouseWheel(evt) {
- if (!this.active) {
- return;
- }
- evt.preventDefault();
- let delta = (0, _ui_utils.normalizeWheelEventDelta)(evt);
- let currentTime = new Date().getTime();
- let storedTime = this.mouseScrollTimeStamp;
- if (currentTime > storedTime && currentTime - storedTime < MOUSE_SCROLL_COOLDOWN_TIME) {
- return;
- }
- if (this.mouseScrollDelta > 0 && delta < 0 || this.mouseScrollDelta < 0 && delta > 0) {
- this._resetMouseScrollState();
- }
- this.mouseScrollDelta += delta;
- if (Math.abs(this.mouseScrollDelta) >= PAGE_SWITCH_THRESHOLD) {
- let totalDelta = this.mouseScrollDelta;
- this._resetMouseScrollState();
- let success = totalDelta > 0 ? this._goToPreviousPage() : this._goToNextPage();
- if (success) {
- this.mouseScrollTimeStamp = currentTime;
- }
- }
- }
- get isFullscreen() {
- return !!(document.fullscreenElement || document.mozFullScreen || document.webkitIsFullScreen || document.msFullscreenElement);
- }
- _goToPreviousPage() {
- let page = this.pdfViewer.currentPageNumber;
- if (page <= 1) {
- return false;
- }
- this.pdfViewer.currentPageNumber = page - 1;
- return true;
- }
- _goToNextPage() {
- let page = this.pdfViewer.currentPageNumber;
- if (page >= this.pdfViewer.pagesCount) {
- return false;
- }
- this.pdfViewer.currentPageNumber = page + 1;
- return true;
- }
- _notifyStateChange() {
- this.eventBus.dispatch('presentationmodechanged', {
- source: this,
- active: this.active,
- switchInProgress: !!this.switchInProgress
- });
- }
- _setSwitchInProgress() {
- if (this.switchInProgress) {
- clearTimeout(this.switchInProgress);
- }
- this.switchInProgress = setTimeout(() => {
- this._removeFullscreenChangeListeners();
- delete this.switchInProgress;
- this._notifyStateChange();
- }, DELAY_BEFORE_RESETTING_SWITCH_IN_PROGRESS);
- }
- _resetSwitchInProgress() {
- if (this.switchInProgress) {
- clearTimeout(this.switchInProgress);
- delete this.switchInProgress;
- }
- }
- _enter() {
- this.active = true;
- this._resetSwitchInProgress();
- this._notifyStateChange();
- this.container.classList.add(ACTIVE_SELECTOR);
- setTimeout(() => {
- this.pdfViewer.currentPageNumber = this.args.page;
- this.pdfViewer.currentScaleValue = 'page-fit';
- }, 0);
- this._addWindowListeners();
- this._showControls();
- this.contextMenuOpen = false;
- this.container.setAttribute('contextmenu', 'viewerContextMenu');
- window.getSelection().removeAllRanges();
- }
- _exit() {
- let page = this.pdfViewer.currentPageNumber;
- this.container.classList.remove(ACTIVE_SELECTOR);
- setTimeout(() => {
- this.active = false;
- this._removeFullscreenChangeListeners();
- this._notifyStateChange();
- this.pdfViewer.currentScaleValue = this.args.previousScale;
- this.pdfViewer.currentPageNumber = page;
- this.args = null;
- }, 0);
- this._removeWindowListeners();
- this._hideControls();
- this._resetMouseScrollState();
- this.container.removeAttribute('contextmenu');
- this.contextMenuOpen = false;
- }
- _mouseDown(evt) {
- if (this.contextMenuOpen) {
- this.contextMenuOpen = false;
- evt.preventDefault();
- return;
- }
- if (evt.button === 0) {
- let isInternalLink = evt.target.href && evt.target.classList.contains('internalLink');
- if (!isInternalLink) {
- evt.preventDefault();
- if (evt.shiftKey) {
- this._goToPreviousPage();
- } else {
- this._goToNextPage();
- }
- }
- }
- }
- _contextMenu() {
- this.contextMenuOpen = true;
- }
- _showControls() {
- if (this.controlsTimeout) {
- clearTimeout(this.controlsTimeout);
- } else {
- this.container.classList.add(CONTROLS_SELECTOR);
- }
- this.controlsTimeout = setTimeout(() => {
- this.container.classList.remove(CONTROLS_SELECTOR);
- delete this.controlsTimeout;
- }, DELAY_BEFORE_HIDING_CONTROLS);
- }
- _hideControls() {
- if (!this.controlsTimeout) {
- return;
- }
- clearTimeout(this.controlsTimeout);
- this.container.classList.remove(CONTROLS_SELECTOR);
- delete this.controlsTimeout;
- }
- _resetMouseScrollState() {
- this.mouseScrollTimeStamp = 0;
- this.mouseScrollDelta = 0;
- }
- _touchSwipe(evt) {
- if (!this.active) {
- return;
- }
- if (evt.touches.length > 1) {
- this.touchSwipeState = null;
- return;
- }
- switch (evt.type) {
- case 'touchstart':
- this.touchSwipeState = {
- startX: evt.touches[0].pageX,
- startY: evt.touches[0].pageY,
- endX: evt.touches[0].pageX,
- endY: evt.touches[0].pageY
- };
- break;
- case 'touchmove':
- if (this.touchSwipeState === null) {
- return;
- }
- this.touchSwipeState.endX = evt.touches[0].pageX;
- this.touchSwipeState.endY = evt.touches[0].pageY;
- evt.preventDefault();
- break;
- case 'touchend':
- if (this.touchSwipeState === null) {
- return;
- }
- let delta = 0;
- let dx = this.touchSwipeState.endX - this.touchSwipeState.startX;
- let dy = this.touchSwipeState.endY - this.touchSwipeState.startY;
- let absAngle = Math.abs(Math.atan2(dy, dx));
- if (Math.abs(dx) > SWIPE_MIN_DISTANCE_THRESHOLD && (absAngle <= SWIPE_ANGLE_THRESHOLD || absAngle >= Math.PI - SWIPE_ANGLE_THRESHOLD)) {
- delta = dx;
- } else if (Math.abs(dy) > SWIPE_MIN_DISTANCE_THRESHOLD && Math.abs(absAngle - Math.PI / 2) <= SWIPE_ANGLE_THRESHOLD) {
- delta = dy;
- }
- if (delta > 0) {
- this._goToPreviousPage();
- } else if (delta < 0) {
- this._goToNextPage();
- }
- break;
- }
- }
- _addWindowListeners() {
- this.showControlsBind = this._showControls.bind(this);
- this.mouseDownBind = this._mouseDown.bind(this);
- this.mouseWheelBind = this._mouseWheel.bind(this);
- this.resetMouseScrollStateBind = this._resetMouseScrollState.bind(this);
- this.contextMenuBind = this._contextMenu.bind(this);
- this.touchSwipeBind = this._touchSwipe.bind(this);
- window.addEventListener('mousemove', this.showControlsBind);
- window.addEventListener('mousedown', this.mouseDownBind);
- window.addEventListener('wheel', this.mouseWheelBind);
- window.addEventListener('keydown', this.resetMouseScrollStateBind);
- window.addEventListener('contextmenu', this.contextMenuBind);
- window.addEventListener('touchstart', this.touchSwipeBind);
- window.addEventListener('touchmove', this.touchSwipeBind);
- window.addEventListener('touchend', this.touchSwipeBind);
- }
- _removeWindowListeners() {
- window.removeEventListener('mousemove', this.showControlsBind);
- window.removeEventListener('mousedown', this.mouseDownBind);
- window.removeEventListener('wheel', this.mouseWheelBind);
- window.removeEventListener('keydown', this.resetMouseScrollStateBind);
- window.removeEventListener('contextmenu', this.contextMenuBind);
- window.removeEventListener('touchstart', this.touchSwipeBind);
- window.removeEventListener('touchmove', this.touchSwipeBind);
- window.removeEventListener('touchend', this.touchSwipeBind);
- delete this.showControlsBind;
- delete this.mouseDownBind;
- delete this.mouseWheelBind;
- delete this.resetMouseScrollStateBind;
- delete this.contextMenuBind;
- delete this.touchSwipeBind;
- }
- _fullscreenChange() {
- if (this.isFullscreen) {
- this._enter();
- } else {
- this._exit();
- }
- }
- _addFullscreenChangeListeners() {
- this.fullscreenChangeBind = this._fullscreenChange.bind(this);
- window.addEventListener('fullscreenchange', this.fullscreenChangeBind);
- window.addEventListener('mozfullscreenchange', this.fullscreenChangeBind);
- }
- _removeFullscreenChangeListeners() {
- window.removeEventListener('fullscreenchange', this.fullscreenChangeBind);
- window.removeEventListener('mozfullscreenchange', this.fullscreenChangeBind);
- delete this.fullscreenChangeBind;
- }
-}
-exports.PDFPresentationMode = PDFPresentationMode;
-
-/***/ }),
-/* 23 */
-/***/ (function(module, exports, __webpack_require__) {
-
-"use strict";
-
-
-Object.defineProperty(exports, "__esModule", {
- value: true
-});
-exports.PDFThumbnailViewer = undefined;
-
-var _ui_utils = __webpack_require__(0);
-
-var _pdf_thumbnail_view = __webpack_require__(24);
-
-const THUMBNAIL_SCROLL_MARGIN = -19;
-class PDFThumbnailViewer {
- constructor({ container, linkService, renderingQueue, l10n = _ui_utils.NullL10n }) {
- this.container = container;
- this.linkService = linkService;
- this.renderingQueue = renderingQueue;
- this.l10n = l10n;
- this.scroll = (0, _ui_utils.watchScroll)(this.container, this._scrollUpdated.bind(this));
- this._resetView();
- }
- _scrollUpdated() {
- this.renderingQueue.renderHighestPriority();
- }
- getThumbnail(index) {
- return this._thumbnails[index];
- }
- _getVisibleThumbs() {
- return (0, _ui_utils.getVisibleElements)(this.container, this._thumbnails);
- }
- scrollThumbnailIntoView(page) {
- let selected = document.querySelector('.thumbnail.selected');
- if (selected) {
- selected.classList.remove('selected');
- }
- let thumbnail = document.querySelector('div.thumbnail[data-page-number="' + page + '"]');
- if (thumbnail) {
- thumbnail.classList.add('selected');
- }
- let visibleThumbs = this._getVisibleThumbs();
- let numVisibleThumbs = visibleThumbs.views.length;
- if (numVisibleThumbs > 0) {
- let first = visibleThumbs.first.id;
- let last = numVisibleThumbs > 1 ? visibleThumbs.last.id : first;
- if (page <= first || page >= last) {
- (0, _ui_utils.scrollIntoView)(thumbnail, { top: THUMBNAIL_SCROLL_MARGIN });
- }
- }
- }
- get pagesRotation() {
- return this._pagesRotation;
- }
- set pagesRotation(rotation) {
- if (!(0, _ui_utils.isValidRotation)(rotation)) {
- throw new Error('Invalid thumbnails rotation angle.');
- }
- if (!this.pdfDocument) {
- return;
- }
- if (this._pagesRotation === rotation) {
- return;
- }
- this._pagesRotation = rotation;
- for (let i = 0, ii = this._thumbnails.length; i < ii; i++) {
- this._thumbnails[i].update(rotation);
- }
- }
- cleanup() {
- _pdf_thumbnail_view.PDFThumbnailView.cleanup();
- }
- _resetView() {
- this._thumbnails = [];
- this._pageLabels = null;
- this._pagesRotation = 0;
- this._pagesRequests = [];
- this.container.textContent = '';
- }
- setDocument(pdfDocument) {
- if (this.pdfDocument) {
- this._cancelRendering();
- this._resetView();
- }
- this.pdfDocument = pdfDocument;
- if (!pdfDocument) {
- return;
- }
- pdfDocument.getPage(1).then(firstPage => {
- let pagesCount = pdfDocument.numPages;
- let viewport = firstPage.getViewport(1.0);
- for (let pageNum = 1; pageNum <= pagesCount; ++pageNum) {
- let thumbnail = new _pdf_thumbnail_view.PDFThumbnailView({
- container: this.container,
- id: pageNum,
- defaultViewport: viewport.clone(),
- linkService: this.linkService,
- renderingQueue: this.renderingQueue,
- disableCanvasToImageConversion: false,
- l10n: this.l10n
- });
- this._thumbnails.push(thumbnail);
- }
- }).catch(reason => {
- console.error('Unable to initialize thumbnail viewer', reason);
- });
- }
- _cancelRendering() {
- for (let i = 0, ii = this._thumbnails.length; i < ii; i++) {
- if (this._thumbnails[i]) {
- this._thumbnails[i].cancelRendering();
- }
- }
- }
- setPageLabels(labels) {
- if (!this.pdfDocument) {
- return;
- }
- if (!labels) {
- this._pageLabels = null;
- } else if (!(labels instanceof Array && this.pdfDocument.numPages === labels.length)) {
- this._pageLabels = null;
- console.error('PDFThumbnailViewer_setPageLabels: Invalid page labels.');
- } else {
- this._pageLabels = labels;
- }
- for (let i = 0, ii = this._thumbnails.length; i < ii; i++) {
- let label = this._pageLabels && this._pageLabels[i];
- this._thumbnails[i].setPageLabel(label);
- }
- }
- _ensurePdfPageLoaded(thumbView) {
- if (thumbView.pdfPage) {
- return Promise.resolve(thumbView.pdfPage);
- }
- let pageNumber = thumbView.id;
- if (this._pagesRequests[pageNumber]) {
- return this._pagesRequests[pageNumber];
- }
- let promise = this.pdfDocument.getPage(pageNumber).then(pdfPage => {
- thumbView.setPdfPage(pdfPage);
- this._pagesRequests[pageNumber] = null;
- return pdfPage;
- }).catch(reason => {
- console.error('Unable to get page for thumb view', reason);
- this._pagesRequests[pageNumber] = null;
- });
- this._pagesRequests[pageNumber] = promise;
- return promise;
- }
- forceRendering() {
- let visibleThumbs = this._getVisibleThumbs();
- let thumbView = this.renderingQueue.getHighestPriority(visibleThumbs, this._thumbnails, this.scroll.down);
- if (thumbView) {
- this._ensurePdfPageLoaded(thumbView).then(() => {
- this.renderingQueue.renderView(thumbView);
- });
- return true;
- }
- return false;
- }
-}
-exports.PDFThumbnailViewer = PDFThumbnailViewer;
-
-/***/ }),
-/* 24 */
-/***/ (function(module, exports, __webpack_require__) {
-
-"use strict";
-
-
-Object.defineProperty(exports, "__esModule", {
- value: true
-});
-exports.PDFThumbnailView = undefined;
-
-var _pdfjsLib = __webpack_require__(1);
-
-var _ui_utils = __webpack_require__(0);
-
-var _pdf_rendering_queue = __webpack_require__(3);
-
-const MAX_NUM_SCALING_STEPS = 3;
-const THUMBNAIL_CANVAS_BORDER_WIDTH = 1;
-const THUMBNAIL_WIDTH = 98;
-const TempImageFactory = function TempImageFactoryClosure() {
- let tempCanvasCache = null;
- return {
- getCanvas(width, height) {
- let tempCanvas = tempCanvasCache;
- if (!tempCanvas) {
- tempCanvas = document.createElement('canvas');
- tempCanvasCache = tempCanvas;
- }
- tempCanvas.width = width;
- tempCanvas.height = height;
- tempCanvas.mozOpaque = true;
- let ctx = tempCanvas.getContext('2d', { alpha: false });
- ctx.save();
- ctx.fillStyle = 'rgb(255, 255, 255)';
- ctx.fillRect(0, 0, width, height);
- ctx.restore();
- return tempCanvas;
- },
- destroyCanvas() {
- let tempCanvas = tempCanvasCache;
- if (tempCanvas) {
- tempCanvas.width = 0;
- tempCanvas.height = 0;
- }
- tempCanvasCache = null;
- }
- };
-}();
-class PDFThumbnailView {
- constructor({ container, id, defaultViewport, linkService, renderingQueue, disableCanvasToImageConversion = false, l10n = _ui_utils.NullL10n }) {
- this.id = id;
- this.renderingId = 'thumbnail' + id;
- this.pageLabel = null;
- this.pdfPage = null;
- this.rotation = 0;
- this.viewport = defaultViewport;
- this.pdfPageRotate = defaultViewport.rotation;
- this.linkService = linkService;
- this.renderingQueue = renderingQueue;
- this.renderTask = null;
- this.renderingState = _pdf_rendering_queue.RenderingStates.INITIAL;
- this.resume = null;
- this.disableCanvasToImageConversion = disableCanvasToImageConversion;
- this.pageWidth = this.viewport.width;
- this.pageHeight = this.viewport.height;
- this.pageRatio = this.pageWidth / this.pageHeight;
- this.canvasWidth = THUMBNAIL_WIDTH;
- this.canvasHeight = this.canvasWidth / this.pageRatio | 0;
- this.scale = this.canvasWidth / this.pageWidth;
- this.l10n = l10n;
- let anchor = document.createElement('a');
- anchor.href = linkService.getAnchorUrl('#page=' + id);
- this.l10n.get('thumb_page_title', { page: id }, 'Page {{page}}').then(msg => {
- anchor.title = msg;
- });
- anchor.onclick = function () {
- linkService.page = id;
- return false;
- };
- this.anchor = anchor;
- let div = document.createElement('div');
- div.className = 'thumbnail';
- div.setAttribute('data-page-number', this.id);
- this.div = div;
- if (id === 1) {
- div.classList.add('selected');
- }
- let ring = document.createElement('div');
- ring.className = 'thumbnailSelectionRing';
- let borderAdjustment = 2 * THUMBNAIL_CANVAS_BORDER_WIDTH;
- ring.style.width = this.canvasWidth + borderAdjustment + 'px';
- ring.style.height = this.canvasHeight + borderAdjustment + 'px';
- this.ring = ring;
- div.appendChild(ring);
- anchor.appendChild(div);
- container.appendChild(anchor);
- }
- setPdfPage(pdfPage) {
- this.pdfPage = pdfPage;
- this.pdfPageRotate = pdfPage.rotate;
- let totalRotation = (this.rotation + this.pdfPageRotate) % 360;
- this.viewport = pdfPage.getViewport(1, totalRotation);
- this.reset();
- }
- reset() {
- this.cancelRendering();
- this.pageWidth = this.viewport.width;
- this.pageHeight = this.viewport.height;
- this.pageRatio = this.pageWidth / this.pageHeight;
- this.canvasHeight = this.canvasWidth / this.pageRatio | 0;
- this.scale = this.canvasWidth / this.pageWidth;
- this.div.removeAttribute('data-loaded');
- let ring = this.ring;
- let childNodes = ring.childNodes;
- for (let i = childNodes.length - 1; i >= 0; i--) {
- ring.removeChild(childNodes[i]);
- }
- let borderAdjustment = 2 * THUMBNAIL_CANVAS_BORDER_WIDTH;
- ring.style.width = this.canvasWidth + borderAdjustment + 'px';
- ring.style.height = this.canvasHeight + borderAdjustment + 'px';
- if (this.canvas) {
- this.canvas.width = 0;
- this.canvas.height = 0;
- delete this.canvas;
- }
- if (this.image) {
- this.image.removeAttribute('src');
- delete this.image;
- }
- }
- update(rotation) {
- if (typeof rotation !== 'undefined') {
- this.rotation = rotation;
- }
- let totalRotation = (this.rotation + this.pdfPageRotate) % 360;
- this.viewport = this.viewport.clone({
- scale: 1,
- rotation: totalRotation
- });
- this.reset();
- }
- cancelRendering() {
- if (this.renderTask) {
- this.renderTask.cancel();
- this.renderTask = null;
- }
- this.renderingState = _pdf_rendering_queue.RenderingStates.INITIAL;
- this.resume = null;
- }
- _getPageDrawContext(noCtxScale = false) {
- let canvas = document.createElement('canvas');
- this.canvas = canvas;
- canvas.mozOpaque = true;
- let ctx = canvas.getContext('2d', { alpha: false });
- let outputScale = (0, _ui_utils.getOutputScale)(ctx);
- canvas.width = this.canvasWidth * outputScale.sx | 0;
- canvas.height = this.canvasHeight * outputScale.sy | 0;
- canvas.style.width = this.canvasWidth + 'px';
- canvas.style.height = this.canvasHeight + 'px';
- if (!noCtxScale && outputScale.scaled) {
- ctx.scale(outputScale.sx, outputScale.sy);
- }
- return ctx;
- }
- _convertCanvasToImage() {
- if (!this.canvas) {
- return;
- }
- if (this.renderingState !== _pdf_rendering_queue.RenderingStates.FINISHED) {
- return;
- }
- let id = this.renderingId;
- let className = 'thumbnailImage';
- if (this.disableCanvasToImageConversion) {
- this.canvas.id = id;
- this.canvas.className = className;
- this.l10n.get('thumb_page_canvas', { page: this.pageId }, 'Thumbnail of Page {{page}}').then(msg => {
- this.canvas.setAttribute('aria-label', msg);
- });
- this.div.setAttribute('data-loaded', true);
- this.ring.appendChild(this.canvas);
- return;
- }
- let image = document.createElement('img');
- image.id = id;
- image.className = className;
- this.l10n.get('thumb_page_canvas', { page: this.pageId }, 'Thumbnail of Page {{page}}').then(msg => {
- image.setAttribute('aria-label', msg);
- });
- image.style.width = this.canvasWidth + 'px';
- image.style.height = this.canvasHeight + 'px';
- image.src = this.canvas.toDataURL();
- this.image = image;
- this.div.setAttribute('data-loaded', true);
- this.ring.appendChild(image);
- this.canvas.width = 0;
- this.canvas.height = 0;
- delete this.canvas;
- }
- draw() {
- if (this.renderingState !== _pdf_rendering_queue.RenderingStates.INITIAL) {
- console.error('Must be in new state before drawing');
- return Promise.resolve(undefined);
- }
- this.renderingState = _pdf_rendering_queue.RenderingStates.RUNNING;
- let renderCapability = (0, _pdfjsLib.createPromiseCapability)();
- let finishRenderTask = error => {
- if (renderTask === this.renderTask) {
- this.renderTask = null;
- }
- if (error instanceof _pdfjsLib.RenderingCancelledException) {
- renderCapability.resolve(undefined);
- return;
- }
- this.renderingState = _pdf_rendering_queue.RenderingStates.FINISHED;
- this._convertCanvasToImage();
- if (!error) {
- renderCapability.resolve(undefined);
- } else {
- renderCapability.reject(error);
- }
- };
- let ctx = this._getPageDrawContext();
- let drawViewport = this.viewport.clone({ scale: this.scale });
- let renderContinueCallback = cont => {
- if (!this.renderingQueue.isHighestPriority(this)) {
- this.renderingState = _pdf_rendering_queue.RenderingStates.PAUSED;
- this.resume = () => {
- this.renderingState = _pdf_rendering_queue.RenderingStates.RUNNING;
- cont();
- };
- return;
- }
- cont();
- };
- let renderContext = {
- canvasContext: ctx,
- viewport: drawViewport
- };
- let renderTask = this.renderTask = this.pdfPage.render(renderContext);
- renderTask.onContinue = renderContinueCallback;
- renderTask.promise.then(function () {
- finishRenderTask(null);
- }, function (error) {
- finishRenderTask(error);
- });
- return renderCapability.promise;
- }
- setImage(pageView) {
- if (this.renderingState !== _pdf_rendering_queue.RenderingStates.INITIAL) {
- return;
- }
- let img = pageView.canvas;
- if (!img) {
- return;
- }
- if (!this.pdfPage) {
- this.setPdfPage(pageView.pdfPage);
- }
- this.renderingState = _pdf_rendering_queue.RenderingStates.FINISHED;
- let ctx = this._getPageDrawContext(true);
- let canvas = ctx.canvas;
- if (img.width <= 2 * canvas.width) {
- ctx.drawImage(img, 0, 0, img.width, img.height, 0, 0, canvas.width, canvas.height);
- this._convertCanvasToImage();
- return;
- }
- let reducedWidth = canvas.width << MAX_NUM_SCALING_STEPS;
- let reducedHeight = canvas.height << MAX_NUM_SCALING_STEPS;
- let reducedImage = TempImageFactory.getCanvas(reducedWidth, reducedHeight);
- let reducedImageCtx = reducedImage.getContext('2d');
- while (reducedWidth > img.width || reducedHeight > img.height) {
- reducedWidth >>= 1;
- reducedHeight >>= 1;
- }
- reducedImageCtx.drawImage(img, 0, 0, img.width, img.height, 0, 0, reducedWidth, reducedHeight);
- while (reducedWidth > 2 * canvas.width) {
- reducedImageCtx.drawImage(reducedImage, 0, 0, reducedWidth, reducedHeight, 0, 0, reducedWidth >> 1, reducedHeight >> 1);
- reducedWidth >>= 1;
- reducedHeight >>= 1;
- }
- ctx.drawImage(reducedImage, 0, 0, reducedWidth, reducedHeight, 0, 0, canvas.width, canvas.height);
- this._convertCanvasToImage();
- }
- get pageId() {
- return this.pageLabel !== null ? this.pageLabel : this.id;
- }
- setPageLabel(label) {
- this.pageLabel = typeof label === 'string' ? label : null;
- this.l10n.get('thumb_page_title', { page: this.pageId }, 'Page {{page}}').then(msg => {
- this.anchor.title = msg;
- });
- if (this.renderingState !== _pdf_rendering_queue.RenderingStates.FINISHED) {
- return;
- }
- this.l10n.get('thumb_page_canvas', { page: this.pageId }, 'Thumbnail of Page {{page}}').then(ariaLabel => {
- if (this.image) {
- this.image.setAttribute('aria-label', ariaLabel);
- } else if (this.disableCanvasToImageConversion && this.canvas) {
- this.canvas.setAttribute('aria-label', ariaLabel);
- }
- });
- }
- static cleanup() {
- TempImageFactory.destroyCanvas();
- }
-}
-exports.PDFThumbnailView = PDFThumbnailView;
-
-/***/ }),
-/* 25 */
+/* 26 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
@@ -7327,17 +7380,17 @@ class SecondaryToolbar {
}
this.toolbarButtonContainer.setAttribute('style', 'max-height: ' + (this.containerHeight - _ui_utils.SCROLLBAR_PADDING) + 'px;');
this.previousContainerHeight = this.containerHeight;
}
}
exports.SecondaryToolbar = SecondaryToolbar;
/***/ }),
-/* 26 */
+/* 27 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
@@ -7512,17 +7565,17 @@ class Toolbar {
container.setAttribute('style', 'min-width: ' + width + 'px; ' + 'max-width: ' + width + 'px;');
}
});
}
}
exports.Toolbar = Toolbar;
/***/ }),
-/* 27 */
+/* 28 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
@@ -7595,32 +7648,32 @@ class ViewHistory {
}
return values;
});
}
}
exports.ViewHistory = ViewHistory;
/***/ }),
-/* 28 */
+/* 29 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.FirefoxCom = exports.DownloadManager = undefined;
-__webpack_require__(29);
+__webpack_require__(30);
var _pdfjsLib = __webpack_require__(1);
-var _preferences = __webpack_require__(30);
+var _preferences = __webpack_require__(31);
var _app = __webpack_require__(4);
;
let FirefoxCom = function FirefoxComClosure() {
return {
requestSync(action, data) {
let request = document.createTextNode('');
@@ -7836,17 +7889,17 @@ document.mozL10n.setExternalLocalizerSer
getStrings(key) {
return FirefoxCom.requestSync('getStrings', key);
}
});
exports.DownloadManager = DownloadManager;
exports.FirefoxCom = FirefoxCom;
/***/ }),
-/* 29 */
+/* 30 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
(function (window) {
var gLanguage = "";
var gExternalLocalizerServices = null;
@@ -7934,17 +7987,17 @@ exports.FirefoxCom = FirefoxCom;
gLanguage = gExternalLocalizerServices.getLocale();
gReadyState = "complete";
},
translate: translateFragment
};
})(undefined);
/***/ }),
-/* 30 */
+/* 31 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
@@ -8059,17 +8112,17 @@ class BasePreferences {
}
return defaultValue;
});
}
}
exports.BasePreferences = BasePreferences;
/***/ }),
-/* 31 */
+/* 32 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
--- a/devtools/client/themes/markup.css
+++ b/devtools/client/themes/markup.css
@@ -1,17 +1,21 @@
/* 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/. */
:root {
+ --markup-hidden-attr-color: var(--theme-comment);
+ --markup-hidden-tag-color: #A1A1A4;
--markup-outline: var(--theme-splitter-color);
}
.theme-dark:root {
+ --markup-hidden-attr-color: var(--theme-body-color-inactive);
+ --markup-hidden-tag-color: var(--theme-content-color1);
--markup-outline: var(--theme-selection-background);
}
* {
padding: 0;
margin: 0;
}
@@ -327,16 +331,26 @@ ul.children + .tag-line::before {
width: .8em;
height: .8em;
margin-top: .3em;
left: 1px;
position: absolute;
z-index: 1;
}
+
+.not-displayed .attr-name,
+.not-displayed .attr-value {
+ color: var(--markup-hidden-attr-color);
+}
+
+.not-displayed .theme-fg-color3 {
+ color: var(--markup-hidden-tag-color);
+}
+
/* Firebug Theme */
.theme-firebug .theme-fg-color3 {
color: var(--theme-graphs-full-blue);
font-weight: normal;
}
.theme-firebug .open,
@@ -348,16 +362,22 @@ ul.children + .tag-line::before {
.theme-firebug .attr-value.theme-fg-color6 {
color: var(--theme-highlight-red);
}
.theme-firebug .markupview-events {
font-size: var(--theme-toolbar-font-size);
}
+/* In case a node isn't displayed in the page, we fade the syntax highlighting */
+.theme-firebug .not-displayed .open,
+.theme-firebug .not-displayed .close {
+ opacity: .5;
+}
+
/* Selected nodes in the tree should have light selected text.
theme-selected doesn't work in this case since the text is a
sibling of the class, not a child. */
.theme-selected ~ .editor,
.theme-selected ~ .editor .theme-fg-color1,
.theme-selected ~ .editor .theme-fg-color2,
.theme-selected ~ .editor .theme-fg-color3,
.theme-selected ~ .editor .theme-fg-color4,
@@ -378,22 +398,16 @@ ul.children + .tag-line::before {
.doctype {
font-style: italic;
}
.theme-firebug .doctype {
color: #787878;
}
-/* In case a node isn't displayed in the page, we fade the syntax highlighting */
-.not-displayed .open,
-.not-displayed .close {
- opacity: .5;
-}
-
/* Events */
.markupview-events {
font-size: 8px;
font-weight: bold;
line-height: 10px;
border-radius: 3px;
padding: 0px 2px;
margin-inline-start: 5px;
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -6627,26 +6627,24 @@ nsDocShell::SetFocus()
NS_IMETHODIMP
nsDocShell::GetMainWidget(nsIWidget** aMainWidget)
{
// We don't create our own widget, so simply return the parent one.
return GetParentWidget(aMainWidget);
}
NS_IMETHODIMP
-nsDocShell::GetTitle(char16_t** aTitle)
-{
- NS_ENSURE_ARG_POINTER(aTitle);
-
- *aTitle = ToNewUnicode(mTitle);
- return NS_OK;
-}
-
-NS_IMETHODIMP
-nsDocShell::SetTitle(const char16_t* aTitle)
+nsDocShell::GetTitle(nsAString& aTitle)
+{
+ aTitle = mTitle;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsDocShell::SetTitle(const nsAString& aTitle)
{
// Store local title
mTitle = aTitle;
nsCOMPtr<nsIDocShellTreeItem> parent;
GetSameTypeParent(getter_AddRefs(parent));
// When title is set on the top object it should then be passed to the
--- a/docshell/base/nsDocShellTreeOwner.cpp
+++ b/docshell/base/nsDocShellTreeOwner.cpp
@@ -715,27 +715,27 @@ nsDocShellTreeOwner::SetFocus()
nsCOMPtr<nsIEmbeddingSiteWindow> ownerWin = GetOwnerWin();
if (ownerWin) {
return ownerWin->SetFocus();
}
return NS_ERROR_NULL_POINTER;
}
NS_IMETHODIMP
-nsDocShellTreeOwner::GetTitle(char16_t** aTitle)
+nsDocShellTreeOwner::GetTitle(nsAString& aTitle)
{
nsCOMPtr<nsIEmbeddingSiteWindow> ownerWin = GetOwnerWin();
if (ownerWin) {
return ownerWin->GetTitle(aTitle);
}
return NS_ERROR_NULL_POINTER;
}
NS_IMETHODIMP
-nsDocShellTreeOwner::SetTitle(const char16_t* aTitle)
+nsDocShellTreeOwner::SetTitle(const nsAString& aTitle)
{
nsCOMPtr<nsIEmbeddingSiteWindow> ownerWin = GetOwnerWin();
if (ownerWin) {
return ownerWin->SetTitle(aTitle);
}
return NS_ERROR_NULL_POINTER;
}
--- a/docshell/base/nsDocShellTreeOwner.h
+++ b/docshell/base/nsDocShellTreeOwner.h
@@ -84,21 +84,16 @@ protected:
nsWebBrowser* WebBrowser();
NS_IMETHOD SetTreeOwner(nsIDocShellTreeOwner* aTreeOwner);
NS_IMETHOD SetWebBrowserChrome(nsIWebBrowserChrome* aWebBrowserChrome);
NS_IMETHOD AddChromeListeners();
NS_IMETHOD RemoveChromeListeners();
- nsresult FindItemWithNameAcrossWindows(
- const char16_t* aName,
- nsIDocShellTreeItem* aRequestor, nsIDocShellTreeItem* aOriginalRequestor,
- nsIDocShellTreeItem** aFoundItem);
-
void EnsurePrompter();
void EnsureAuthPrompter();
void AddToWatcher();
void RemoveFromWatcher();
void EnsureContentTreeOwner();
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -7336,17 +7336,17 @@ nsDocument::DoNotifyPossibleTitleChange(
nsCOMPtr<nsIPresShell> shell = GetShell();
if (shell) {
nsCOMPtr<nsISupports> container =
shell->GetPresContext()->GetContainerWeak();
if (container) {
nsCOMPtr<nsIBaseWindow> docShellWin = do_QueryInterface(container);
if (docShellWin) {
- docShellWin->SetTitle(title.get());
+ docShellWin->SetTitle(title);
}
}
}
// Fire a DOM event for the title change.
nsContentUtils::DispatchChromeEvent(this, static_cast<nsIDocument*>(this),
NS_LITERAL_STRING("DOMTitleChanged"),
true, true);
--- a/dom/base/nsRange.cpp
+++ b/dom/base/nsRange.cpp
@@ -1043,22 +1043,29 @@ IndexOf(nsINode* aChild)
}
void
nsRange::SetSelection(mozilla::dom::Selection* aSelection)
{
if (mSelection == aSelection) {
return;
}
+
// At least one of aSelection and mSelection must be null
// aSelection will be null when we are removing from a selection
// and a range can't be in more than one selection at a time,
// thus mSelection must be null too.
MOZ_ASSERT(!aSelection || !mSelection);
+ // Extra step in case our parent failed to ensure the above
+ // invariant.
+ if (aSelection && mSelection) {
+ mSelection->RemoveRange(this);
+ }
+
mSelection = aSelection;
if (mSelection) {
nsINode* commonAncestor = GetCommonAncestor();
NS_ASSERTION(commonAncestor, "unexpected disconnected nodes");
RegisterCommonAncestor(commonAncestor);
} else {
UnregisterCommonAncestor(mRegisteredCommonAncestor, false);
MOZ_DIAGNOSTIC_ASSERT(!mRegisteredCommonAncestor,
--- a/dom/base/nsWindowMemoryReporter.cpp
+++ b/dom/base/nsWindowMemoryReporter.cpp
@@ -297,291 +297,249 @@ CollectWindowReports(nsGlobalWindow *aWi
// Use |windowPath|, but replace "explicit/" with "event-counts/".
nsCString censusWindowPath(windowPath);
censusWindowPath.Replace(0, strlen("explicit"), "event-counts");
// Remember the path for later.
aWindowPaths->Put(aWindow->WindowID(), windowPath);
-#define REPORT_SIZE(_pathTail, _amount, _desc) \
+// Report the size from windowSizes and add to the appropriate total in
+// aWindowTotalSizes.
+#define REPORT_SIZE(_pathTail, _field, _desc) \
+ ReportSize(windowPath, _pathTail, windowSizes._field, \
+ NS_LITERAL_CSTRING(_desc), aHandleReport, aData); \
+ aWindowTotalSizes->_field += windowSizes._field;
+
+// Report the size, which is a sum of other sizes, and so doesn't require
+// updating aWindowTotalSizes.
+#define REPORT_SUM_SIZE(_pathTail, _amount, _desc) \
ReportSize(windowPath, _pathTail, _amount, NS_LITERAL_CSTRING(_desc), \
aHandleReport, aData);
-#define REPORT_COUNT(_pathTail, _amount, _desc) \
- ReportCount(censusWindowPath, _pathTail, _amount, NS_LITERAL_CSTRING(_desc), \
- aHandleReport, aData);
+// Like REPORT_SIZE, but for a count.
+#define REPORT_COUNT(_pathTail, _field, _desc) \
+ ReportCount(censusWindowPath, _pathTail, windowSizes._field, \
+ NS_LITERAL_CSTRING(_desc), aHandleReport, aData); \
+ aWindowTotalSizes->_field += windowSizes._field;
// This SizeOfState contains the SeenPtrs used for all memory reporting of
// this window.
SizeOfState state(WindowsMallocSizeOf);
nsWindowSizes windowSizes(state);
aWindow->AddSizeOfIncludingThis(windowSizes);
- REPORT_SIZE("/dom/element-nodes", windowSizes.mDOMElementNodesSize,
+ REPORT_SIZE("/dom/element-nodes", mDOMElementNodesSize,
"Memory used by the element nodes in a window's DOM.");
- aWindowTotalSizes->mDOMElementNodesSize += windowSizes.mDOMElementNodesSize;
- REPORT_SIZE("/dom/text-nodes", windowSizes.mDOMTextNodesSize,
+ REPORT_SIZE("/dom/text-nodes", mDOMTextNodesSize,
"Memory used by the text nodes in a window's DOM.");
- aWindowTotalSizes->mDOMTextNodesSize += windowSizes.mDOMTextNodesSize;
- REPORT_SIZE("/dom/cdata-nodes", windowSizes.mDOMCDATANodesSize,
+ REPORT_SIZE("/dom/cdata-nodes", mDOMCDATANodesSize,
"Memory used by the CDATA nodes in a window's DOM.");
- aWindowTotalSizes->mDOMCDATANodesSize += windowSizes.mDOMCDATANodesSize;
- REPORT_SIZE("/dom/comment-nodes", windowSizes.mDOMCommentNodesSize,
+ REPORT_SIZE("/dom/comment-nodes", mDOMCommentNodesSize,
"Memory used by the comment nodes in a window's DOM.");
- aWindowTotalSizes->mDOMCommentNodesSize += windowSizes.mDOMCommentNodesSize;
- REPORT_SIZE("/dom/event-targets", windowSizes.mDOMEventTargetsSize,
+ REPORT_SIZE("/dom/event-targets", mDOMEventTargetsSize,
"Memory used by the event targets table in a window's DOM, and "
"the objects it points to, which include XHRs.");
- aWindowTotalSizes->mDOMEventTargetsSize += windowSizes.mDOMEventTargetsSize;
- REPORT_SIZE("/dom/performance/user-entries",
- windowSizes.mDOMPerformanceUserEntries,
+ REPORT_SIZE("/dom/performance/user-entries", mDOMPerformanceUserEntries,
"Memory used for performance user entries.");
- aWindowTotalSizes->mDOMPerformanceUserEntries +=
- windowSizes.mDOMPerformanceUserEntries;
REPORT_SIZE("/dom/performance/resource-entries",
- windowSizes.mDOMPerformanceResourceEntries,
+ mDOMPerformanceResourceEntries,
"Memory used for performance resource entries.");
- aWindowTotalSizes->mDOMPerformanceResourceEntries +=
- windowSizes.mDOMPerformanceResourceEntries;
- REPORT_SIZE("/dom/other", windowSizes.mDOMOtherSize,
+ REPORT_SIZE("/dom/other", mDOMOtherSize,
"Memory used by a window's DOM that isn't measured by the "
"other 'dom/' numbers.");
- aWindowTotalSizes->mDOMOtherSize += windowSizes.mDOMOtherSize;
- REPORT_SIZE("/layout/style-sheets", windowSizes.mLayoutStyleSheetsSize,
+ REPORT_SIZE("/layout/style-sheets", mLayoutStyleSheetsSize,
"Memory used by style sheets within a window.");
- aWindowTotalSizes->mLayoutStyleSheetsSize +=
- windowSizes.mLayoutStyleSheetsSize;
- REPORT_SIZE("/layout/pres-shell", windowSizes.mLayoutPresShellSize,
+ REPORT_SIZE("/layout/pres-shell", mLayoutPresShellSize,
"Memory used by layout's PresShell, along with any structures "
"allocated in its arena and not measured elsewhere, "
"within a window.");
- aWindowTotalSizes->mLayoutPresShellSize += windowSizes.mLayoutPresShellSize;
- REPORT_SIZE("/layout/gecko-style-sets", windowSizes.mLayoutGeckoStyleSets,
+ REPORT_SIZE("/layout/gecko-style-sets", mLayoutGeckoStyleSets,
"Memory used by Gecko style sets within a window.");
- aWindowTotalSizes->mLayoutGeckoStyleSets += windowSizes.mLayoutGeckoStyleSets;
REPORT_SIZE("/layout/servo-style-sets/stylist/rule-tree",
- windowSizes.mLayoutServoStyleSetsStylistRuleTree,
+ mLayoutServoStyleSetsStylistRuleTree,
"Memory used by rule trees within Servo style sets within a "
"window.");
- aWindowTotalSizes->mLayoutServoStyleSetsStylistRuleTree +=
- windowSizes.mLayoutServoStyleSetsStylistRuleTree;
REPORT_SIZE("/layout/servo-style-sets/stylist/element-and-pseudos-maps",
- windowSizes.mLayoutServoStyleSetsStylistElementAndPseudosMaps,
+ mLayoutServoStyleSetsStylistElementAndPseudosMaps,
"Memory used by element and pseudos maps within Servo style "
"sets within a window.");
- aWindowTotalSizes->mLayoutServoStyleSetsStylistElementAndPseudosMaps +=
- windowSizes.mLayoutServoStyleSetsStylistElementAndPseudosMaps;
REPORT_SIZE("/layout/servo-style-sets/stylist/invalidation-map",
- windowSizes.mLayoutServoStyleSetsStylistInvalidationMap,
+ mLayoutServoStyleSetsStylistInvalidationMap,
"Memory used by invalidation maps within Servo style sets "
"within a window.");
- aWindowTotalSizes->mLayoutServoStyleSetsStylistInvalidationMap +=
- windowSizes.mLayoutServoStyleSetsStylistInvalidationMap;
REPORT_SIZE("/layout/servo-style-sets/stylist/revalidation-selectors",
- windowSizes.mLayoutServoStyleSetsStylistRevalidationSelectors,
+ mLayoutServoStyleSetsStylistRevalidationSelectors,
"Memory used by selectors for cache revalidation within Servo "
"style sets within a window.");
- aWindowTotalSizes->mLayoutServoStyleSetsStylistRevalidationSelectors +=
- windowSizes.mLayoutServoStyleSetsStylistRevalidationSelectors;
REPORT_SIZE("/layout/servo-style-sets/stylist/other",
- windowSizes.mLayoutServoStyleSetsStylistOther,
+ mLayoutServoStyleSetsStylistOther,
"Memory used by other Stylist data within Servo style sets "
"within a window.");
- aWindowTotalSizes->mLayoutServoStyleSetsStylistOther +=
- windowSizes.mLayoutServoStyleSetsStylistOther;
- REPORT_SIZE("/layout/servo-style-sets/other",
- windowSizes.mLayoutServoStyleSetsOther,
+ REPORT_SIZE("/layout/servo-style-sets/other", mLayoutServoStyleSetsOther,
"Memory used by other parts of Servo style sets within a "
"window.");
- aWindowTotalSizes->mLayoutServoStyleSetsOther +=
- windowSizes.mLayoutServoStyleSetsOther;
REPORT_SIZE("/layout/servo-element-data-objects",
- windowSizes.mLayoutServoElementDataObjects,
+ mLayoutServoElementDataObjects,
"Memory used for Servo ElementData objects, but not the things"
"hanging off them.");
- aWindowTotalSizes->mLayoutServoElementDataObjects +=
- windowSizes.mLayoutServoElementDataObjects;
- REPORT_SIZE("/layout/text-runs", windowSizes.mLayoutTextRunsSize,
+ REPORT_SIZE("/layout/text-runs", mLayoutTextRunsSize,
"Memory used for text-runs (glyph layout) in the PresShell's "
"frame tree, within a window.");
- aWindowTotalSizes->mLayoutTextRunsSize += windowSizes.mLayoutTextRunsSize;
- REPORT_SIZE("/layout/pres-contexts", windowSizes.mLayoutPresContextSize,
+ REPORT_SIZE("/layout/pres-contexts", mLayoutPresContextSize,
"Memory used for the PresContext in the PresShell's frame "
"within a window.");
- aWindowTotalSizes->mLayoutPresContextSize +=
- windowSizes.mLayoutPresContextSize;
- REPORT_SIZE("/layout/frame-properties",
- windowSizes.mLayoutFramePropertiesSize,
+ REPORT_SIZE("/layout/frame-properties", mLayoutFramePropertiesSize,
"Memory used for frame properties attached to frames "
"within a window.");
- aWindowTotalSizes->mLayoutFramePropertiesSize +=
- windowSizes.mLayoutFramePropertiesSize;
- REPORT_SIZE("/layout/computed-values/dom",
- windowSizes.mLayoutComputedValuesDom,
+ REPORT_SIZE("/layout/computed-values/dom", mLayoutComputedValuesDom,
"Memory used by ComputedValues objects accessible from DOM "
"elements.");
- aWindowTotalSizes->mLayoutComputedValuesDom +=
- windowSizes.mLayoutComputedValuesDom;
- REPORT_SIZE("/layout/computed-values/non-dom",
- windowSizes.mLayoutComputedValuesNonDom,
+ REPORT_SIZE("/layout/computed-values/non-dom", mLayoutComputedValuesNonDom,
"Memory used by ComputedValues objects not accessible from DOM "
"elements.");
- aWindowTotalSizes->mLayoutComputedValuesNonDom +=
- windowSizes.mLayoutComputedValuesNonDom;
- REPORT_SIZE("/layout/computed-values/visited",
- windowSizes.mLayoutComputedValuesVisited,
+ REPORT_SIZE("/layout/computed-values/visited", mLayoutComputedValuesVisited,
"Memory used by ComputedValues objects used for visited styles.");
- aWindowTotalSizes->mLayoutComputedValuesVisited +=
- windowSizes.mLayoutComputedValuesVisited;
- REPORT_SIZE("/property-tables",
- windowSizes.mPropertyTablesSize,
+ REPORT_SIZE("/property-tables", mPropertyTablesSize,
"Memory used for the property tables within a window.");
- aWindowTotalSizes->mPropertyTablesSize += windowSizes.mPropertyTablesSize;
- REPORT_COUNT("/dom/event-targets", windowSizes.mDOMEventTargetsCount,
+ REPORT_COUNT("/dom/event-targets", mDOMEventTargetsCount,
"Number of non-node event targets in the event targets table "
"in a window's DOM, such as XHRs.");
- aWindowTotalSizes->mDOMEventTargetsCount +=
- windowSizes.mDOMEventTargetsCount;
- REPORT_COUNT("/dom/event-listeners", windowSizes.mDOMEventListenersCount,
+ REPORT_COUNT("/dom/event-listeners", mDOMEventListenersCount,
"Number of event listeners in a window, including event "
"listeners on nodes and other event targets.");
- aWindowTotalSizes->mDOMEventListenersCount +=
- windowSizes.mDOMEventListenersCount;
- REPORT_SIZE("/layout/line-boxes", windowSizes.mArenaSizes.mLineBoxes,
+ REPORT_SIZE("/layout/line-boxes", mArenaSizes.mLineBoxes,
"Memory used by line boxes within a window.");
- aWindowTotalSizes->mArenaSizes.mLineBoxes
- += windowSizes.mArenaSizes.mLineBoxes;
- REPORT_SIZE("/layout/rule-nodes", windowSizes.mArenaSizes.mRuleNodes,
+ REPORT_SIZE("/layout/rule-nodes", mArenaSizes.mRuleNodes,
"Memory used by CSS rule nodes within a window.");
- aWindowTotalSizes->mArenaSizes.mRuleNodes
- += windowSizes.mArenaSizes.mRuleNodes;
- REPORT_SIZE("/layout/style-contexts", windowSizes.mArenaSizes.mStyleContexts,
+ REPORT_SIZE("/layout/style-contexts", mArenaSizes.mStyleContexts,
"Memory used by style contexts within a window.");
- aWindowTotalSizes->mArenaSizes.mStyleContexts
- += windowSizes.mArenaSizes.mStyleContexts;
// There are many different kinds of style structs, but it is likely that
// only a few matter. Implement a cutoff so we don't bloat about:memory with
// many uninteresting entries.
const size_t STYLE_SUNDRIES_THRESHOLD =
js::MemoryReportingSundriesThreshold();
// This is the Gecko style structs, which are in the nsPresArena.
size_t geckoStyleSundriesSize = 0;
#define STYLE_STRUCT(name_, cb_) \
{ \
size_t size = \
windowSizes.mArenaSizes.mGeckoStyleSizes.NS_STYLE_SIZES_FIELD(name_); \
if (size < STYLE_SUNDRIES_THRESHOLD) { \
geckoStyleSundriesSize += size; \
} else { \
- REPORT_SIZE("/layout/gecko-style-structs/" # name_, size, \
- "Memory used by the " #name_ " Gecko style structs " \
- "within a window."); \
+ REPORT_SUM_SIZE( \
+ "/layout/gecko-style-structs/" # name_, size, \
+ "Memory used by the " #name_ " Gecko style structs within a window."); \
} \
aWindowTotalSizes->mArenaSizes.mGeckoStyleSizes.NS_STYLE_SIZES_FIELD(name_) += \
size; \
}
#define STYLE_STRUCT_LIST_IGNORE_VARIABLES
#include "nsStyleStructList.h"
#undef STYLE_STRUCT
#undef STYLE_STRUCT_LIST_IGNORE_VARIABLES
if (geckoStyleSundriesSize > 0) {
- REPORT_SIZE("/layout/gecko-style-structs/sundries", geckoStyleSundriesSize,
- "The sum of all memory used by Gecko style structs which were "
- "too small to be shown individually.");
+ REPORT_SUM_SIZE(
+ "/layout/gecko-style-structs/sundries", geckoStyleSundriesSize,
+ "The sum of all memory used by Gecko style structs which were too small "
+ "to be shown individually.");
}
// There are many different kinds of frames, but it is very likely
// that only a few matter. Implement a cutoff so we don't bloat
// about:memory with many uninteresting entries.
const size_t FRAME_SUNDRIES_THRESHOLD =
js::MemoryReportingSundriesThreshold();
size_t frameSundriesSize = 0;
#define FRAME_ID(classname, ...) \
{ \
size_t size = windowSizes.mArenaSizes.NS_ARENA_SIZES_FIELD(classname); \
if (size < FRAME_SUNDRIES_THRESHOLD) { \
frameSundriesSize += size; \
} else { \
- REPORT_SIZE("/layout/frames/" # classname, size, \
- "Memory used by frames of " \
- "type " #classname " within a window."); \
+ REPORT_SUM_SIZE( \
+ "/layout/frames/" # classname, size, \
+ "Memory used by frames of type " #classname " within a window."); \
} \
aWindowTotalSizes->mArenaSizes.NS_ARENA_SIZES_FIELD(classname) += size; \
}
#define ABSTRACT_FRAME_ID(...)
#include "nsFrameIdList.h"
#undef FRAME_ID
#undef ABSTRACT_FRAME_ID
if (frameSundriesSize > 0) {
- REPORT_SIZE("/layout/frames/sundries", frameSundriesSize,
- "The sum of all memory used by frames which were too small "
- "to be shown individually.");
+ REPORT_SUM_SIZE(
+ "/layout/frames/sundries", frameSundriesSize,
+ "The sum of all memory used by frames which were too small to be shown "
+ "individually.");
}
// This is the Servo style structs.
size_t servoStyleSundriesSize = 0;
#define STYLE_STRUCT(name_, cb_) \
{ \
size_t size = windowSizes.mServoStyleSizes.NS_STYLE_SIZES_FIELD(name_); \
if (size < STYLE_SUNDRIES_THRESHOLD) { \
servoStyleSundriesSize += size; \
} else { \
- REPORT_SIZE("/layout/servo-style-structs/" # name_, size, \
- "Memory used by the " #name_ " Servo style structs " \
- "within a window."); \
+ REPORT_SUM_SIZE( \
+ "/layout/servo-style-structs/" # name_, size, \
+ "Memory used by the " #name_ " Servo style structs within a window."); \
} \
aWindowTotalSizes->mServoStyleSizes.NS_STYLE_SIZES_FIELD(name_) += size; \
}
#define STYLE_STRUCT_LIST_IGNORE_VARIABLES
#include "nsStyleStructList.h"
#undef STYLE_STRUCT
#undef STYLE_STRUCT_LIST_IGNORE_VARIABLES
if (servoStyleSundriesSize > 0) {
- REPORT_SIZE("/layout/servo-style-structs/sundries", servoStyleSundriesSize,
- "The sum of all memory used by Servo style structs which were "
- "too small to be shown individually.");
+ REPORT_SUM_SIZE(
+ "/layout/servo-style-structs/sundries", servoStyleSundriesSize,
+ "The sum of all memory used by Servo style structs which were too "
+ "small to be shown individually.");
}
#undef REPORT_SIZE
+#undef REPORT_SUM_SIZE
#undef REPORT_COUNT
}
typedef nsTArray< RefPtr<nsGlobalWindow> > WindowArray;
NS_IMETHODIMP
nsWindowMemoryReporter::CollectReports(nsIHandleReportCallback* aHandleReport,
nsISupports* aData, bool aAnonymize)
--- a/dom/base/nsXHTMLContentSerializer.cpp
+++ b/dom/base/nsXHTMLContentSerializer.cpp
@@ -661,27 +661,22 @@ nsXHTMLContentSerializer::LineBreakAfter
}
if ((aName == nsGkAtoms::html) ||
(aName == nsGkAtoms::head) ||
(aName == nsGkAtoms::body) ||
(aName == nsGkAtoms::tr) ||
(aName == nsGkAtoms::th) ||
(aName == nsGkAtoms::td) ||
- (aName == nsGkAtoms::pre) ||
(aName == nsGkAtoms::title) ||
- (aName == nsGkAtoms::li) ||
(aName == nsGkAtoms::dt) ||
(aName == nsGkAtoms::dd) ||
- (aName == nsGkAtoms::blockquote) ||
(aName == nsGkAtoms::select) ||
(aName == nsGkAtoms::option) ||
- (aName == nsGkAtoms::p) ||
- (aName == nsGkAtoms::map) ||
- (aName == nsGkAtoms::div)) {
+ (aName == nsGkAtoms::map)) {
return true;
}
return nsHTMLElement::IsBlock(nsHTMLTags::CaseSensitiveAtomTagToId(aName));
}
void
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -409,17 +409,17 @@ TabChild::TabChild(nsIContentChild* aMan
, mTabGroup(aTabGroup)
, mRemoteFrame(nullptr)
, mManager(aManager)
, mChromeFlags(aChromeFlags)
, mMaxTouchPoints(0)
, mActiveSuppressDisplayport(0)
, mLayersId(0)
, mBeforeUnloadListeners(0)
- , mLayersConnected(true)
+ , mLayersConnected(false)
, mDidFakeShow(false)
, mNotified(false)
, mTriedBrowserInit(false)
, mOrientation(eScreenOrientation_PortraitPrimary)
, mIgnoreKeyPressEvent(false)
, mHasValidInnerSize(false)
, mDestroyed(false)
, mUniqueId(aTabId)
@@ -936,25 +936,25 @@ TabChild::GetVisibility(bool* aVisibilit
NS_IMETHODIMP
TabChild::SetVisibility(bool aVisibility)
{
// should the platform support this? Bug 666365
return NS_OK;
}
NS_IMETHODIMP
-TabChild::GetTitle(char16_t** aTitle)
+TabChild::GetTitle(nsAString& aTitle)
{
NS_WARNING("TabChild::GetTitle not supported in TabChild");
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
-TabChild::SetTitle(const char16_t* aTitle)
+TabChild::SetTitle(const nsAString& aTitle)
{
// JavaScript sends the "DOMTitleChanged" event to the parent
// via the message manager.
return NS_OK;
}
NS_IMETHODIMP
TabChild::GetSiteWindow(void** aSiteWindow)
@@ -1169,16 +1169,17 @@ TabChild::RecvLoadURL(const nsCString& a
}
void
TabChild::DoFakeShow(const TextureFactoryIdentifier& aTextureFactoryIdentifier,
const uint64_t& aLayersId,
const CompositorOptions& aCompositorOptions,
PRenderFrameChild* aRenderFrame, const ShowInfo& aShowInfo)
{
+ mLayersConnected = aRenderFrame ? true : false;
InitRenderingState(aTextureFactoryIdentifier, aLayersId, aCompositorOptions, aRenderFrame);
RecvShow(ScreenIntSize(0, 0), aShowInfo, mParentIsActive, nsSizeMode_Normal);
mDidFakeShow = true;
}
void
TabChild::ApplyShowInfo(const ShowInfo& aInfo)
{
@@ -2792,31 +2793,30 @@ TabChild::InitRenderingState(const Textu
if (!sTabChildren) {
sTabChildren = new TabChildMap;
}
MOZ_ASSERT(!sTabChildren->Get(aLayersId));
sTabChildren->Put(aLayersId, this);
mLayersId = aLayersId;
}
- ShadowLayerForwarder* lf =
- mPuppetWidget->GetLayerManager(
- nullptr, mTextureFactoryIdentifier.mParentBackend)
- ->AsShadowForwarder();
-
LayerManager* lm = mPuppetWidget->GetLayerManager();
if (lm->AsWebRenderLayerManager()) {
lm->AsWebRenderLayerManager()->Initialize(compositorChild,
wr::AsPipelineId(aLayersId),
&mTextureFactoryIdentifier);
ImageBridgeChild::IdentifyCompositorTextureHost(mTextureFactoryIdentifier);
gfx::VRManagerChild::IdentifyTextureHost(mTextureFactoryIdentifier);
InitAPZState();
}
+ ShadowLayerForwarder* lf =
+ mPuppetWidget->GetLayerManager(
+ nullptr, mTextureFactoryIdentifier.mParentBackend)
+ ->AsShadowForwarder();
if (lf) {
nsTArray<LayersBackend> backends;
backends.AppendElement(mTextureFactoryIdentifier.mParentBackend);
PLayerTransactionChild* shadowManager =
compositorChild->SendPLayerTransactionConstructor(backends, aLayersId);
if (shadowManager) {
lf->SetShadowManager(shadowManager);
lf->IdentifyTextureHost(mTextureFactoryIdentifier);
@@ -3162,16 +3162,17 @@ TabChild::ReinitRendering()
});
}
if (!success) {
NS_WARNING("failed to recreate layer manager");
return;
}
+ mLayersConnected = true;
ImageBridgeChild::IdentifyCompositorTextureHost(mTextureFactoryIdentifier);
gfx::VRManagerChild::IdentifyTextureHost(mTextureFactoryIdentifier);
InitAPZState();
nsCOMPtr<nsIDocument> doc(GetDocument());
doc->NotifyLayerManagerRecreated();
}
new file mode 100644
--- /dev/null
+++ b/dom/svg/crashtests/1347617-1.svg
@@ -0,0 +1,10 @@
+<svg height='600'
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ filter="url(#f)">
+
+<filter id="f" filterRes="19" filterUnits="userSpaceOnUse">
+<feConvolveMatrix kernelMatrix="1 1 1 1 1 1 1 1 1" kernelUnitLength="1 -1" />
+</filter>
+
+</svg>
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/dom/svg/crashtests/1347617-2.svg
@@ -0,0 +1,10 @@
+<svg height='600'
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ filter="url(#f)">
+
+<filter id="f" filterRes="19" filterUnits="userSpaceOnUse">
+<feConvolveMatrix kernelMatrix="1 1 1 1 1 1 1 1 1" kernelUnitLength="-1 1" />
+</filter>
+
+</svg>
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/dom/svg/crashtests/1347617-3.svg
@@ -0,0 +1,10 @@
+<svg height='600'
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ filter="url(#f)">
+
+<filter id="f" filterRes="19" filterUnits="userSpaceOnUse">
+<feConvolveMatrix kernelMatrix="1 1 1 1 1 1 1 1 1" kernelUnitLength="-1" />
+</filter>
+
+</svg>
\ No newline at end of file
--- a/dom/svg/crashtests/crashtests.list
+++ b/dom/svg/crashtests/crashtests.list
@@ -85,8 +85,11 @@ load 1322286.html
load 1329849-1.svg
load 1329849-2.svg
load 1329849-3.svg
load 1329849-4.svg
load 1329849-5.svg
load 1329849-6.svg
load 1329093-1.html
load 1329093-2.html
+load 1347617-1.svg
+load 1347617-2.svg
+load 1347617-3.svg
--- a/dom/webbrowserpersist/nsWebBrowserPersist.cpp
+++ b/dom/webbrowserpersist/nsWebBrowserPersist.cpp
@@ -8,16 +8,17 @@
#include "nspr.h"
#include "nsIFileStreams.h" // New Necko file streams
#include <algorithm>
#include "nsAutoPtr.h"
#include "nsNetCID.h"
#include "nsNetUtil.h"
+#include "nsIClassOfService.h"
#include "nsIInterfaceRequestorUtils.h"
#include "nsILoadContext.h"
#include "nsIPrivateBrowsingChannel.h"
#include "nsComponentManagerUtils.h"
#include "nsIComponentRegistrar.h"
#include "nsIStorageStream.h"
#include "nsISeekableStream.h"
#include "nsIHttpChannel.h"
@@ -1492,16 +1493,22 @@ nsresult nsWebBrowserPersist::SaveChanne
rv = NS_NewBufferedInputStream(getter_AddRefs(bufferedInputStream),
fileInputStream, BUFFERED_OUTPUT_SIZE);
NS_ENSURE_SUCCESS(rv, rv);
nsAutoCString contentType;
aChannel->GetContentType(contentType);
return StartUpload(bufferedInputStream, aFile, contentType);
}
+ // Mark save channel as throttleable.
+ nsCOMPtr<nsIClassOfService> cos(do_QueryInterface(aChannel));
+ if (cos) {
+ cos->AddClassFlags(nsIClassOfService::Throttleable);
+ }
+
// Read from the input channel
nsresult rv = NS_MaybeOpenChannelUsingAsyncOpen2(aChannel, this);
if (rv == NS_ERROR_NO_CONTENT)
{
// Assume this is a protocol such as mailto: which does not feed out
// data and just ignore it.
return NS_SUCCESS_DONT_FIXUP;
}
--- a/extensions/cookie/test/unit/test_cookies_sync_failure.js
+++ b/extensions/cookie/test/unit/test_cookies_sync_failure.js
@@ -13,17 +13,17 @@
// 4) Migration fails. This will have different modes depending on the initial
// version:
// a) Schema 1: the 'lastAccessed' column already exists.
// b) Schema 2: the 'baseDomain' column already exists; or 'baseDomain'
// cannot be computed for a particular host.
// c) Schema 3: the 'creationTime' column already exists; or the
// 'moz_uniqueid' index already exists.
-var COOKIE_DATABASE_SCHEMA_CURRENT = 8;
+var COOKIE_DATABASE_SCHEMA_CURRENT = 9;
var test_generator = do_run_test();
function run_test() {
do_test_pending();
do_run_generator(test_generator);
}
--- a/gfx/layers/wr/IpcResourceUpdateQueue.cpp
+++ b/gfx/layers/wr/IpcResourceUpdateQueue.cpp
@@ -177,16 +177,20 @@ ShmSegmentsReader::ReadLarge(const layer
aInto.PushBytes(Range<uint8_t>(srcPtr, aRange.length()));
return true;
}
bool
ShmSegmentsReader::Read(const layers::OffsetRange& aRange, wr::Vec_u8& aInto)
{
+ if (aRange.length() == 0) {
+ return true;
+ }
+
if (aRange.source() != 0) {
return ReadLarge(aRange, aInto);
}
if (mChunkSize == 0) {
return false;
}
--- a/image/decoders/nsPNGDecoder.cpp
+++ b/image/decoders/nsPNGDecoder.cpp
@@ -279,16 +279,17 @@ nsPNGDecoder::InitInternal()
bool(GetSurfaceFlags() & SurfaceFlags::NO_PREMULTIPLY_ALPHA);
#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED
static png_byte color_chunks[]=
{ 99, 72, 82, 77, '\0', // cHRM
105, 67, 67, 80, '\0'}; // iCCP
static png_byte unused_chunks[]=
{ 98, 75, 71, 68, '\0', // bKGD
+ 101, 88, 73, 102, '\0', // eXIf
104, 73, 83, 84, '\0', // hIST
105, 84, 88, 116, '\0', // iTXt
111, 70, 70, 115, '\0', // oFFs
112, 67, 65, 76, '\0', // pCAL
115, 67, 65, 76, '\0', // sCAL
112, 72, 89, 115, '\0', // pHYs
115, 66, 73, 84, '\0', // sBIT
115, 80, 76, 84, '\0', // sPLT
new file mode 100644
--- /dev/null
+++ b/intl/icu-patches/bug-1387476-timezone-detection.diff
@@ -0,0 +1,67 @@
+Update time detection for newer Linux distros and macOS 10.13
+
+https://ssl.icu-project.org/trac/ticket/12770
+https://ssl.icu-project.org/trac/changeset/40427
+https://ssl.icu-project.org/trac/changeset/40432
+https://ssl.icu-project.org/trac/changeset?old=40300&old_path=trunk%2Ficu4c%2Fsource%2Fcommon%2Fputil.cpp&new_path=trunk%2Ficu4c%2Fsource%2Fcommon%2Fputil.cpp&new=40432
+
+Index: /intl/icu/source/common/putil.cpp
+===================================================================
+--- /intl/icu/source/common/putil.cpp (revision 40300)
++++ /intl/icu/source/common/putil.cpp (revision 40432)
+@@ -676,4 +676,14 @@
+ #if !UCONFIG_NO_FILE_IO && ((U_PLATFORM_IS_DARWIN_BASED && (U_PLATFORM != U_PF_IPHONE || defined(U_TIMEZONE))) || U_PLATFORM_IS_LINUX_BASED || U_PLATFORM == U_PF_BSD || U_PLATFORM == U_PF_SOLARIS)
+ /* These platforms are likely to use Olson timezone IDs. */
++/* common targets of the symbolic link at TZDEFAULT are:
++ * "/usr/share/zoneinfo/<olsonID>" default, older Linus distros, macOS to 10.12
++ * "../usr/share/zoneinfo/<olsonID>" newer Linux distros: Red Hat Enterprise Linux 7, Ubuntu, SuSe Linux
++ * "/usr/share/lib/zoneinfo/<olsonID>" Solaris
++ * "../usr/share/lib/zoneinfo/<olsonID>" Solaris
++ * "/var/db/timezone/zoneinfo/<olsonID>" macOS 10.13
++ * To avoid checking lots of paths, just check that the target path
++ * before the <olsonID> ends with "/zoneinfo/", and the <olsonID> is valid.
++ */
++
+ #define CHECK_LOCALTIME_LINK 1
+ #if U_PLATFORM_IS_DARWIN_BASED
+@@ -683,5 +693,4 @@
+ #define TZDEFAULT "/etc/localtime"
+ #define TZZONEINFO "/usr/share/lib/zoneinfo/"
+-#define TZZONEINFO2 "../usr/share/lib/zoneinfo/"
+ #define TZ_ENV_CHECK "localtime"
+ #else
+@@ -689,4 +698,5 @@
+ #define TZZONEINFO "/usr/share/zoneinfo/"
+ #endif
++#define TZZONEINFOTAIL "/zoneinfo/"
+ #if U_HAVE_DIRENT_H
+ #define TZFILE_SKIP "posixrules" /* tz file to skip when searching. */
+@@ -1132,22 +1142,13 @@
+ int32_t ret = (int32_t)readlink(TZDEFAULT, gTimeZoneBuffer, sizeof(gTimeZoneBuffer)-1);
+ if (0 < ret) {
+- int32_t tzZoneInfoLen = uprv_strlen(TZZONEINFO);
++ int32_t tzZoneInfoTailLen = uprv_strlen(TZZONEINFOTAIL);
+ gTimeZoneBuffer[ret] = 0;
+- if (uprv_strncmp(gTimeZoneBuffer, TZZONEINFO, tzZoneInfoLen) == 0
+- && isValidOlsonID(gTimeZoneBuffer + tzZoneInfoLen))
++ char * tzZoneInfoTailPtr = uprv_strstr(gTimeZoneBuffer, TZZONEINFOTAIL);
++
++ if (tzZoneInfoTailPtr != NULL
++ && isValidOlsonID(tzZoneInfoTailPtr + tzZoneInfoTailLen))
+ {
+- return (gTimeZoneBufferPtr = gTimeZoneBuffer + tzZoneInfoLen);
++ return (gTimeZoneBufferPtr = tzZoneInfoTailPtr + tzZoneInfoTailLen);
+ }
+-#if U_PLATFORM == U_PF_SOLARIS
+- else
+- {
+- tzZoneInfoLen = uprv_strlen(TZZONEINFO2);
+- if (uprv_strncmp(gTimeZoneBuffer, TZZONEINFO2, tzZoneInfoLen) == 0
+- && isValidOlsonID(gTimeZoneBuffer + tzZoneInfoLen))
+- {
+- return (gTimeZoneBufferPtr = gTimeZoneBuffer + tzZoneInfoLen);
+- }
+- }
+-#endif
+ } else {
+ #if defined(SEARCH_TZFILE)
--- a/intl/icu/source/common/putil.cpp
+++ b/intl/icu/source/common/putil.cpp
@@ -670,29 +670,39 @@ uprv_timezone()
#if defined(U_TZNAME) && (U_PLATFORM == U_PF_IRIX || U_PLATFORM_IS_DARWIN_BASED)
/* RS6000 and others reject char **tzname. */
extern U_IMPORT char *U_TZNAME[];
#endif
#if !UCONFIG_NO_FILE_IO && ((U_PLATFORM_IS_DARWIN_BASED && (U_PLATFORM != U_PF_IPHONE || defined(U_TIMEZONE))) || U_PLATFORM_IS_LINUX_BASED || U_PLATFORM == U_PF_BSD || U_PLATFORM == U_PF_SOLARIS)
/* These platforms are likely to use Olson timezone IDs. */
+/* common targets of the symbolic link at TZDEFAULT are:
+ * "/usr/share/zoneinfo/<olsonID>" default, older Linus distros, macOS to 10.12
+ * "../usr/share/zoneinfo/<olsonID>" newer Linux distros: Red Hat Enterprise Linux 7, Ubuntu, SuSe Linux
+ * "/usr/share/lib/zoneinfo/<olsonID>" Solaris
+ * "../usr/share/lib/zoneinfo/<olsonID>" Solaris
+ * "/var/db/timezone/zoneinfo/<olsonID>" macOS 10.13
+ * To avoid checking lots of paths, just check that the target path
+ * before the <olsonID> ends with "/zoneinfo/", and the <olsonID> is valid.
+ */
+
#define CHECK_LOCALTIME_LINK 1
#if U_PLATFORM_IS_DARWIN_BASED
#include <tzfile.h>
#define TZZONEINFO (TZDIR "/")
#elif U_PLATFORM == U_PF_SOLARIS
#define TZDEFAULT "/etc/localtime"
#define TZZONEINFO "/usr/share/lib/zoneinfo/"
-#define TZZONEINFO2 "../usr/share/lib/zoneinfo/"
#define TZ_ENV_CHECK "localtime"
#else
#define TZDEFAULT "/etc/localtime"
#define TZZONEINFO "/usr/share/zoneinfo/"
#endif
+#define TZZONEINFOTAIL "/zoneinfo/"
#if U_HAVE_DIRENT_H
#define TZFILE_SKIP "posixrules" /* tz file to skip when searching. */
/* Some Linux distributions have 'localtime' in /usr/share/zoneinfo
symlinked to /etc/localtime, which makes searchForTZFile return
'localtime' when it's the first match. */
#define TZFILE_SKIP2 "localtime"
#define SEARCH_TZFILE
#include <dirent.h> /* Needed to search through system timezone files */
@@ -1120,34 +1130,25 @@ uprv_tzname(int n)
if (gTimeZoneBufferPtr == NULL) {
/*
This is a trick to look at the name of the link to get the Olson ID
because the tzfile contents is underspecified.
This isn't guaranteed to work because it may not be a symlink.
*/
int32_t ret = (int32_t)readlink(TZDEFAULT, gTimeZoneBuffer, sizeof(gTimeZoneBuffer)-1);
if (0 < ret) {
- int32_t tzZoneInfoLen = uprv_strlen(TZZONEINFO);
+ int32_t tzZoneInfoTailLen = uprv_strlen(TZZONEINFOTAIL);
gTimeZoneBuffer[ret] = 0;
- if (uprv_strncmp(gTimeZoneBuffer, TZZONEINFO, tzZoneInfoLen) == 0
- && isValidOlsonID(gTimeZoneBuffer + tzZoneInfoLen))
+ char * tzZoneInfoTailPtr = uprv_strstr(gTimeZoneBuffer, TZZONEINFOTAIL);
+
+ if (tzZoneInfoTailPtr != NULL
+ && isValidOlsonID(tzZoneInfoTailPtr + tzZoneInfoTailLen))
{
- return (gTimeZoneBufferPtr = gTimeZoneBuffer + tzZoneInfoLen);
+ return (gTimeZoneBufferPtr = tzZoneInfoTailPtr + tzZoneInfoTailLen);
}
-#if U_PLATFORM == U_PF_SOLARIS
- else
- {
- tzZoneInfoLen = uprv_strlen(TZZONEINFO2);
- if (uprv_strncmp(gTimeZoneBuffer, TZZONEINFO2, tzZoneInfoLen) == 0
- && isValidOlsonID(gTimeZoneBuffer + tzZoneInfoLen))
- {
- return (gTimeZoneBufferPtr = gTimeZoneBuffer + tzZoneInfoLen);
- }
- }
-#endif
} else {
#if defined(SEARCH_TZFILE)
DefaultTZInfo* tzInfo = (DefaultTZInfo*)uprv_malloc(sizeof(DefaultTZInfo));
if (tzInfo != NULL) {
tzInfo->defaultTZBuffer = NULL;
tzInfo->defaultTZFileSize = 0;
tzInfo->defaultTZFilePtr = NULL;
tzInfo->defaultTZstatus = FALSE;
--- a/intl/update-icu.sh
+++ b/intl/update-icu.sh
@@ -69,16 +69,17 @@ for patch in \
bug-915735 \
suppress-warnings.diff \
bug-1172609-timezone-recreateDefault.diff \
bug-1198952-workaround-make-3.82-bug.diff \
u_setMemoryFunctions-callconvention-anachronism-msvc.diff \
bug-1373763-convertToPosix-stack-value-out-of-scope.diff \
bug-1380083 \
bug-1387937.diff \
+ bug-1387476-timezone-detection.diff \
; do
echo "Applying local patch $patch"
patch -d ${icu_dir}/../../ -p1 --no-backup-if-mismatch < ${icu_dir}/../icu-patches/$patch
done
topsrcdir=`dirname $0`/../
python ${topsrcdir}/js/src/tests/ecma_6/String/make-normalize-generateddata-input.py $topsrcdir
--- a/js/public/RootingAPI.h
+++ b/js/public/RootingAPI.h
@@ -137,16 +137,22 @@ template <typename T> struct IsHeapConst
template <> struct IsHeapConstructibleType<T> { static constexpr bool value = true; };
FOR_EACH_PUBLIC_GC_POINTER_TYPE(DECLARE_IS_HEAP_CONSTRUCTIBLE_TYPE)
FOR_EACH_PUBLIC_TAGGED_GC_POINTER_TYPE(DECLARE_IS_HEAP_CONSTRUCTIBLE_TYPE)
#undef DECLARE_IS_HEAP_CONSTRUCTIBLE_TYPE
template <typename T, typename Wrapper>
class PersistentRootedBase : public MutableWrappedPtrOperations<T, Wrapper> {};
+template <typename T>
+class FakeRooted;
+
+template <typename T>
+class FakeMutableHandle;
+
namespace gc {
struct Cell;
template<typename T>
struct PersistentRootedMarker;
} /* namespace gc */
// Important: Return a reference so passing a Rooted<T>, etc. to
// something that takes a |const T&| is not a GC hazard.
@@ -899,74 +905,16 @@ class RootedBase<JSObject*, Container> :
template <typename Container>
class HandleBase<JSObject*, Container> : public WrappedPtrOperations<JSObject*, Container>
{
public:
template <class U>
JS::Handle<U*> as() const;
};
-/** Interface substitute for Rooted<T> which does not root the variable's memory. */
-template <typename T>
-class MOZ_RAII FakeRooted : public RootedBase<T, FakeRooted<T>>
-{
- public:
- using ElementType = T;
-
- template <typename CX>
- explicit FakeRooted(CX* cx) : ptr(JS::GCPolicy<T>::initial()) {}
-
- template <typename CX>
- FakeRooted(CX* cx, T initial) : ptr(initial) {}
-
- DECLARE_POINTER_CONSTREF_OPS(T);
- DECLARE_POINTER_ASSIGN_OPS(FakeRooted, T);
- DECLARE_NONPOINTER_ACCESSOR_METHODS(ptr);
- DECLARE_NONPOINTER_MUTABLE_ACCESSOR_METHODS(ptr);
-
- private:
- T ptr;
-
- void set(const T& value) {
- ptr = value;
- }
-
- FakeRooted(const FakeRooted&) = delete;
-};
-
-/** Interface substitute for MutableHandle<T> which is not required to point to rooted memory. */
-template <typename T>
-class FakeMutableHandle : public js::MutableHandleBase<T, FakeMutableHandle<T>>
-{
- public:
- using ElementType = T;
-
- MOZ_IMPLICIT FakeMutableHandle(T* t) {
- ptr = t;
- }
-
- MOZ_IMPLICIT FakeMutableHandle(FakeRooted<T>* root) {
- ptr = root->address();
- }
-
- void set(const T& v) {
- *ptr = v;
- }
-
- DECLARE_POINTER_CONSTREF_OPS(T);
- DECLARE_NONPOINTER_ACCESSOR_METHODS(*ptr);
- DECLARE_NONPOINTER_MUTABLE_ACCESSOR_METHODS(*ptr);
-
- private:
- FakeMutableHandle() {}
- DELETE_ASSIGNMENT_OPS(FakeMutableHandle, T);
-
- T* ptr;
-};
-
/**
* Types for a variable that either should or shouldn't be rooted, depending on
* the template parameter allowGC. Used for implementing functions that can
* operate on either rooted or unrooted data.
*
* The toHandle() and toMutableHandle() functions are for calling functions
* which require handle types and are only called in the CanGC case. These
* allow the calling code to type check.
@@ -996,37 +944,16 @@ template <typename T> class MaybeRooted<
}
template <typename T2>
static inline JS::Handle<T2*> downcastHandle(HandleType v) {
return v.template as<T2>();
}
};
-template <typename T> class MaybeRooted<T, NoGC>
-{
- public:
- typedef const T& HandleType;
- typedef FakeRooted<T> RootType;
- typedef FakeMutableHandle<T> MutableHandleType;
-
- static JS::Handle<T> toHandle(HandleType v) {
- MOZ_CRASH("Bad conversion");
- }
-
- static JS::MutableHandle<T> toMutableHandle(MutableHandleType v) {
- MOZ_CRASH("Bad conversion");
- }
-
- template <typename T2>
- static inline T2* downcastHandle(HandleType v) {
- return &v->template as<T2>();
- }
-};
-
} /* namespace js */
namespace JS {
template <typename T> template <typename S>
inline
Handle<T>::Handle(const Rooted<S>& root,
typename mozilla::EnableIf<mozilla::IsConvertible<S, T>::value, int>::Type dummy)
@@ -1514,11 +1441,9 @@ operator==(const T& a, std::nullptr_t b)
template <typename T>
typename mozilla::EnableIf<js::detail::DefineComparisonOps<T>::value &&
mozilla::IsPointer<typename T::ElementType>::value, bool>::Type
operator!=(const T& a, std::nullptr_t b) {
return !(a == b);
}
-#undef DELETE_ASSIGNMENT_OPS
-
#endif /* js_RootingAPI_h */
--- a/js/src/builtin/Promise.cpp
+++ b/js/src/builtin/Promise.cpp
@@ -466,39 +466,39 @@ PromiseHasAnyFlag(PromiseObject& promise
return promise.getFixedSlot(PromiseSlot_Flags).toInt32() & flag;
}
static bool ResolvePromiseFunction(JSContext* cx, unsigned argc, Value* vp);
static bool RejectPromiseFunction(JSContext* cx, unsigned argc, Value* vp);
// ES2016, 25.4.1.3.
static MOZ_MUST_USE bool
-CreateResolvingFunctions(JSContext* cx, HandleValue promise,
- MutableHandleValue resolveVal,
- MutableHandleValue rejectVal)
+CreateResolvingFunctions(JSContext* cx, HandleObject promise,
+ MutableHandleObject resolveFn,
+ MutableHandleObject rejectFn)
{
RootedAtom funName(cx, cx->names().empty);
RootedFunction resolve(cx, NewNativeFunction(cx, ResolvePromiseFunction, 1, funName,
gc::AllocKind::FUNCTION_EXTENDED, GenericObject));
if (!resolve)
return false;
RootedFunction reject(cx, NewNativeFunction(cx, RejectPromiseFunction, 1, funName,
gc::AllocKind::FUNCTION_EXTENDED, GenericObject));
if (!reject)
return false;
- resolve->setExtendedSlot(ResolveFunctionSlot_Promise, promise);
+ resolve->setExtendedSlot(ResolveFunctionSlot_Promise, ObjectValue(*promise));
resolve->setExtendedSlot(ResolveFunctionSlot_RejectFunction, ObjectValue(*reject));
- reject->setExtendedSlot(RejectFunctionSlot_Promise, promise);
+ reject->setExtendedSlot(RejectFunctionSlot_Promise, ObjectValue(*promise));
reject->setExtendedSlot(RejectFunctionSlot_ResolveFunction, ObjectValue(*resolve));
- resolveVal.setObject(*resolve);
- rejectVal.setObject(*reject);
+ resolveFn.set(resolve);
+ rejectFn.set(reject);
return true;
}
static void ClearResolutionFunctionSlots(JSFunction* resolutionFun);
static MOZ_MUST_USE bool RejectMaybeWrappedPromise(JSContext *cx, HandleObject promiseObj,
HandleValue reason);
@@ -855,16 +855,42 @@ CreatePromiseObjectWithoutResolutionFunc
if (!promise)
return nullptr;
AddPromiseFlags(*promise, PROMISE_FLAG_DEFAULT_RESOLVE_FUNCTION |
PROMISE_FLAG_DEFAULT_REJECT_FUNCTION);
return promise;
}
+static MOZ_MUST_USE PromiseObject*
+CreatePromiseWithDefaultResolutionFunctions(JSContext* cx, MutableHandleObject resolve,
+ MutableHandleObject reject)
+{
+ // ES2016, 25.4.3.1., as if called with GetCapabilitiesExecutor as the
+ // executor argument.
+
+ // Steps 1-2 (Not applicable).
+
+ // Steps 3-7.
+ Rooted<PromiseObject*> promise(cx, CreatePromiseObjectInternal(cx));
+ if (!promise)
+ return nullptr;
+
+ // Step 8.
+ if (!CreateResolvingFunctions(cx, promise, resolve, reject))
+ return nullptr;
+
+ promise->setFixedSlot(PromiseSlot_RejectFunction, ObjectValue(*reject));
+
+ // Steps 9-10 (Not applicable).
+
+ // Step 11.
+ return promise;
+}
+
// ES2016, 25.4.1.5.
static MOZ_MUST_USE bool
NewPromiseCapability(JSContext* cx, HandleObject C, MutableHandleObject promise,
MutableHandleObject resolve, MutableHandleObject reject,
bool canOmitResolutionFunctions)
{
RootedValue cVal(cx, ObjectValue(*C));
@@ -878,18 +904,25 @@ NewPromiseCapability(JSContext* cx, Hand
// resolve/reject functions won't ever escape to content, we can skip
// creating and calling the executor function and instead return a Promise
// marked as having default resolve/reject functions.
//
// This can't be used in Promise.all and Promise.race because we have to
// pass the reject (and resolve, in the race case) function to thenables
// in the list passed to all/race, which (potentially) means exposing them
// to content.
- if (canOmitResolutionFunctions && IsNativeFunction(cVal, PromiseConstructor)) {
- promise.set(CreatePromiseObjectWithoutResolutionFunctions(cx));
+ //
+ // For Promise.all and Promise.race we can only optimize away the creation
+ // of the GetCapabilitiesExecutor function, and directly allocate the
+ // result promise instead of invoking the Promise constructor.
+ if (IsNativeFunction(cVal, PromiseConstructor)) {
+ if (canOmitResolutionFunctions)
+ promise.set(CreatePromiseObjectWithoutResolutionFunctions(cx));
+ else
+ promise.set(CreatePromiseWithDefaultResolutionFunctions(cx, resolve, reject));
if (!promise)
return false;
return true;
}
// Step 3 (omitted).
// Step 4.
@@ -1250,42 +1283,43 @@ PromiseResolveThenableJob(JSContext* cx,
CallArgs args = CallArgsFromVp(argc, vp);
RootedFunction job(cx, &args.callee().as<JSFunction>());
RootedValue then(cx, job->getExtendedSlot(ThenableJobSlot_Handler));
MOZ_ASSERT(!IsWrapper(&then.toObject()));
RootedNativeObject jobArgs(cx, &job->getExtendedSlot(ThenableJobSlot_JobData)
.toObject().as<NativeObject>());
- RootedValue promise(cx, jobArgs->getDenseElement(ThenableJobDataIndex_Promise));
+ RootedObject promise(cx, &jobArgs->getDenseElement(ThenableJobDataIndex_Promise).toObject());
RootedValue thenable(cx, jobArgs->getDenseElement(ThenableJobDataIndex_Thenable));
// Step 1.
- RootedValue resolveVal(cx);
- RootedValue rejectVal(cx);
- if (!CreateResolvingFunctions(cx, promise, &resolveVal, &rejectVal))
+ RootedObject resolveFn(cx);
+ RootedObject rejectFn(cx);
+ if (!CreateResolvingFunctions(cx, promise, &resolveFn, &rejectFn))
return false;
// Step 2.
FixedInvokeArgs<2> args2(cx);
- args2[0].set(resolveVal);
- args2[1].set(rejectVal);
+ args2[0].setObject(*resolveFn);
+ args2[1].setObject(*rejectFn);
RootedValue rval(cx);
// In difference to the usual pattern, we return immediately on success.
if (Call(cx, then, thenable, args2, &rval))
return true;
if (!MaybeGetAndClearException(cx, &rval))
return false;
FixedInvokeArgs<1> rejectArgs(cx);
rejectArgs[0].set(rval);
+ RootedValue rejectVal(cx, ObjectValue(*rejectFn));
return Call(cx, rejectVal, UndefinedHandleValue, rejectArgs, &rval);
}
/**
* Tells the embedding to enqueue a Promise resolve thenable job, based on
* three parameters:
* promiseToResolve_ - The promise to resolve, obviously.
* thenable_ - The thenable to resolve the Promise with.
@@ -1580,64 +1614,64 @@ PromiseObject::create(JSContext* cx, Han
// Steps 3-7.
Rooted<PromiseObject*> promise(cx, CreatePromiseObjectInternal(cx, usedProto, needsWrapping,
false));
if (!promise)
return nullptr;
- RootedValue promiseVal(cx, ObjectValue(*promise));
- if (needsWrapping && !cx->compartment()->wrap(cx, &promiseVal))
+ RootedObject promiseObj(cx, promise);
+ if (needsWrapping && !cx->compartment()->wrap(cx, &promiseObj))
return nullptr;
// Step 8.
// The resolving functions are created in the compartment active when the
// (maybe wrapped) Promise constructor was called. They contain checks and
// can unwrap the Promise if required.
- RootedValue resolveVal(cx);
- RootedValue rejectVal(cx);
- if (!CreateResolvingFunctions(cx, promiseVal, &resolveVal, &rejectVal))
+ RootedObject resolveFn(cx);
+ RootedObject rejectFn(cx);
+ if (!CreateResolvingFunctions(cx, promiseObj, &resolveFn, &rejectFn))
return nullptr;
// Need to wrap the resolution functions before storing them on the Promise.
if (needsWrapping) {
AutoCompartment ac(cx, promise);
- RootedValue wrappedRejectVal(cx, rejectVal);
- if (!cx->compartment()->wrap(cx, &wrappedRejectVal))
+ RootedObject wrappedRejectFn(cx, rejectFn);
+ if (!cx->compartment()->wrap(cx, &wrappedRejectFn))
return nullptr;
- promise->setFixedSlot(PromiseSlot_RejectFunction, wrappedRejectVal);
+ promise->setFixedSlot(PromiseSlot_RejectFunction, ObjectValue(*wrappedRejectFn));
} else {
- promise->setFixedSlot(PromiseSlot_RejectFunction, rejectVal);
+ promise->setFixedSlot(PromiseSlot_RejectFunction, ObjectValue(*rejectFn));
}
// Step 9.
bool success;
{
FixedInvokeArgs<2> args(cx);
- args[0].set(resolveVal);
- args[1].set(rejectVal);
+ args[0].setObject(*resolveFn);
+ args[1].setObject(*rejectFn);
RootedValue calleeOrRval(cx, ObjectValue(*executor));
success = Call(cx, calleeOrRval, UndefinedHandleValue, args, &calleeOrRval);
}
// Step 10.
if (!success) {
RootedValue exceptionVal(cx);
if (!MaybeGetAndClearException(cx, &exceptionVal))
return nullptr;
FixedInvokeArgs<1> args(cx);
args[0].set(exceptionVal);
- // |rejectVal| is unused after this, so we can safely write to it.
- if (!Call(cx, rejectVal, UndefinedHandleValue, args, &rejectVal))
+ RootedValue calleeOrRval(cx, ObjectValue(*rejectFn));
+ if (!Call(cx, calleeOrRval, UndefinedHandleValue, args, &calleeOrRval))
return nullptr;
}
// Let the Debugger know about this Promise.
JS::dbg::onNewPromise(cx, promise);
// Step 11.
return promise;
@@ -1993,17 +2027,17 @@ PerformPromiseAll(JSContext *cx, JS::For
return false;
}
// Step i.
// Sadly, because someone could have overridden
// "resolve" on the canonical Promise constructor.
RootedValue nextPromise(cx);
RootedValue staticResolve(cx);
- if (!GetProperty(cx, CVal, cx->names().resolve, &staticResolve))
+ if (!GetProperty(cx, C, CVal, cx->names().resolve, &staticResolve))
return false;
FixedInvokeArgs<1> resolveArgs(cx);
resolveArgs[0].set(nextValue);
if (!Call(cx, staticResolve, CVal, resolveArgs, &nextPromise))
return false;
// Step j.
@@ -2202,17 +2236,17 @@ PerformPromiseRace(JSContext *cx, JS::Fo
return true;
}
// Step h.
// Sadly, because someone could have overridden
// "resolve" on the canonical Promise constructor.
RootedValue nextPromise(cx);
RootedValue staticResolve(cx);
- if (!GetProperty(cx, CVal, cx->names().resolve, &staticResolve))
+ if (!GetProperty(cx, C, CVal, cx->names().resolve, &staticResolve))
return false;
FixedInvokeArgs<1> resolveArgs(cx);
resolveArgs[0].set(nextValue);
if (!Call(cx, staticResolve, CVal, resolveArgs, &nextPromise))
return false;
// Step i.
@@ -3035,25 +3069,25 @@ PerformPromiseThenWithReaction(JSContext
* the call to |promise.then| would use the original |Promise| constructor to
* create the resulting promise, this function skips the call to |promise.then|
* and thus creating a new promise that would not be observable by content.
*/
static MOZ_MUST_USE bool
BlockOnPromise(JSContext* cx, HandleValue promiseVal, HandleObject blockedPromise_,
HandleValue onFulfilled, HandleValue onRejected)
{
- RootedValue thenVal(cx);
- if (!GetProperty(cx, promiseVal, cx->names().then, &thenVal))
+ RootedObject promiseObj(cx, ToObject(cx, promiseVal));
+ if (!promiseObj)
return false;
- RootedObject promiseObj(cx);
- if (promiseVal.isObject())
- promiseObj = &promiseVal.toObject();
-
- if (promiseObj && promiseObj->is<PromiseObject>() && IsNativeFunction(thenVal, Promise_then)) {
+ RootedValue thenVal(cx);
+ if (!GetProperty(cx, promiseObj, promiseVal, cx->names().then, &thenVal))
+ return false;
+
+ if (promiseObj->is<PromiseObject>() && IsNativeFunction(thenVal, Promise_then)) {
// |promise| is an unwrapped Promise, and |then| is the original
// |Promise.prototype.then|, inline it here.
// 25.4.5.3., step 3.
RootedObject PromiseCtor(cx);
if (!GetBuiltinConstructor(cx, JSProto_Promise, &PromiseCtor))
return false;
RootedObject C(cx, SpeciesConstructor(cx, promiseObj, JSProto_Promise, IsPromiseSpecies));
@@ -3093,17 +3127,17 @@ BlockOnPromise(JSContext* cx, HandleValu
return false;
}
// In case the value to depend on isn't an object at all, there's nothing
// more to do here: we can only add reactions to Promise objects
// (potentially after unwrapping them), and non-object values can't be
// Promise objects. This can happen if Promise.all is called on an object
// with a `resolve` method that returns primitives.
- if (!promiseObj)
+ if (!promiseVal.isObject())
return true;
// The object created by the |promise.then| call or the inlined version
// of it above is visible to content (either because |promise.then| was
// overridden by content and could leak it, or because a constructor
// other than the original value of |Promise| was used to create it).
// To have both that object and |blockedPromise| show up as dependent
// promises in the debugger, add a dummy reaction to the list of reject
--- a/js/src/gc/Rooting.h
+++ b/js/src/gc/Rooting.h
@@ -76,11 +76,90 @@ typedef JS::Rooted<DebuggerFrame*>
typedef JS::Rooted<DebuggerObject*> RootedDebuggerObject;
typedef JS::Rooted<Scope*> RootedScope;
typedef JS::GCVector<JSFunction*> FunctionVector;
typedef JS::GCVector<PropertyName*> PropertyNameVector;
typedef JS::GCVector<Shape*> ShapeVector;
typedef JS::GCVector<JSString*> StringVector;
+/** Interface substitute for Rooted<T> which does not root the variable's memory. */
+template <typename T>
+class MOZ_RAII FakeRooted : public RootedBase<T, FakeRooted<T>>
+{
+ public:
+ using ElementType = T;
+
+ template <typename CX>
+ explicit FakeRooted(CX* cx) : ptr(JS::GCPolicy<T>::initial()) {}
+
+ template <typename CX>
+ FakeRooted(CX* cx, T initial) : ptr(initial) {}
+
+ DECLARE_POINTER_CONSTREF_OPS(T);
+ DECLARE_POINTER_ASSIGN_OPS(FakeRooted, T);
+ DECLARE_NONPOINTER_ACCESSOR_METHODS(ptr);
+ DECLARE_NONPOINTER_MUTABLE_ACCESSOR_METHODS(ptr);
+
+ private:
+ T ptr;
+
+ void set(const T& value) {
+ ptr = value;
+ }
+
+ FakeRooted(const FakeRooted&) = delete;
+};
+
+/** Interface substitute for MutableHandle<T> which is not required to point to rooted memory. */
+template <typename T>
+class FakeMutableHandle : public js::MutableHandleBase<T, FakeMutableHandle<T>>
+{
+ public:
+ using ElementType = T;
+
+ MOZ_IMPLICIT FakeMutableHandle(T* t) {
+ ptr = t;
+ }
+
+ MOZ_IMPLICIT FakeMutableHandle(FakeRooted<T>* root) {
+ ptr = root->address();
+ }
+
+ void set(const T& v) {
+ *ptr = v;
+ }
+
+ DECLARE_POINTER_CONSTREF_OPS(T);
+ DECLARE_NONPOINTER_ACCESSOR_METHODS(*ptr);
+ DECLARE_NONPOINTER_MUTABLE_ACCESSOR_METHODS(*ptr);
+
+ private:
+ FakeMutableHandle() {}
+ DELETE_ASSIGNMENT_OPS(FakeMutableHandle, T);
+
+ T* ptr;
+};
+
+template <typename T> class MaybeRooted<T, NoGC>
+{
+ public:
+ typedef const T& HandleType;
+ typedef FakeRooted<T> RootType;
+ typedef FakeMutableHandle<T> MutableHandleType;
+
+ static JS::Handle<T> toHandle(HandleType v) {
+ MOZ_CRASH("Bad conversion");
+ }
+
+ static JS::MutableHandle<T> toMutableHandle(MutableHandleType v) {
+ MOZ_CRASH("Bad conversion");
+ }
+
+ template <typename T2>
+ static inline T2* downcastHandle(HandleType v) {
+ return &v->template as<T2>();
+ }
+};
+
} /* namespace js */
#endif /* gc_Rooting_h */
--- a/js/src/jit/IonAnalysis.cpp
+++ b/js/src/jit/IonAnalysis.cpp
@@ -4261,17 +4261,17 @@ jit::AnalyzeNewScriptDefiniteProperties(
ReportOutOfMemory(cx);
return false;
}
MDefinition* thisValue = graph.entryBlock()->getSlot(info.thisSlot());
// Get a list of instructions using the |this| value in the order they
// appear in the graph.
- Vector<MInstruction*> instructions(cx);
+ Vector<MInstruction*, 4> instructions(cx);
for (MUseDefIterator uses(thisValue); uses; uses++) {
MDefinition* use = uses.def();
// Don't track |this| through assignments to phis.
if (!use->isInstruction())
return true;
--- a/js/src/jit/MoveResolver.h
+++ b/js/src/jit/MoveResolver.h
@@ -211,17 +211,18 @@ class MoveOp
{ }
MoveOp(const MoveOperand& from, const MoveOperand& to, Type type)
: from_(from),
to_(to),
cycleBegin_(false),
cycleEnd_(false),
cycleBeginSlot_(-1),
cycleEndSlot_(-1),
- type_(type)
+ type_(type),
+ endCycleType_(GENERAL) // initialize to silence UBSan warning
{ }
bool isCycleBegin() const {
return cycleBegin_;
}
bool isCycleEnd() const {
return cycleEnd_;
}
--- a/js/src/jsscript.cpp
+++ b/js/src/jsscript.cpp
@@ -3152,17 +3152,17 @@ size_t
JSScript::sizeOfData(mozilla::MallocSizeOf mallocSizeOf) const
{
return mallocSizeOf(data);
}
size_t
JSScript::sizeOfTypeScript(mozilla::MallocSizeOf mallocSizeOf) const
{
- return types_->sizeOfIncludingThis(mallocSizeOf);
+ return types_ ? types_->sizeOfIncludingThis(mallocSizeOf) : 0;
}
/*
* Nb: srcnotes are variable-length. This function computes the number of
* srcnote *slots*, which may be greater than the number of srcnotes.
*/
uint32_t
JSScript::numNotes()
--- a/js/src/vm/Interpreter.cpp
+++ b/js/src/vm/Interpreter.cpp
@@ -2512,34 +2512,34 @@ CASE(JSOP_GE)
if (!GreaterThanOrEqualOperation(cx, lval, rval, &cond))
goto error;
TRY_BRANCH_AFTER_COND(cond, 2);
REGS.sp[-2].setBoolean(cond);
REGS.sp--;
}
END_CASE(JSOP_GE)
-#define SIGNED_SHIFT_OP(OP) \
+#define SIGNED_SHIFT_OP(OP, TYPE) \
JS_BEGIN_MACRO \
int32_t i, j; \
if (!ToInt32(cx, REGS.stackHandleAt(-2), &i)) \
goto error; \
if (!ToInt32(cx, REGS.stackHandleAt(-1), &j)) \
goto error; \
- i = i OP (j & 31); \
+ i = TYPE(i) OP (j & 31); \
REGS.sp--; \
REGS.sp[-1].setInt32(i); \
JS_END_MACRO
CASE(JSOP_LSH)
- SIGNED_SHIFT_OP(<<);
+ SIGNED_SHIFT_OP(<<, uint32_t);
END_CASE(JSOP_LSH)
CASE(JSOP_RSH)
- SIGNED_SHIFT_OP(>>);
+ SIGNED_SHIFT_OP(>>, int32_t);
END_CASE(JSOP_RSH)
#undef SIGNED_SHIFT_OP
CASE(JSOP_URSH)
{
HandleValue lval = REGS.stackHandleAt(-2);
HandleValue rval = REGS.stackHandleAt(-1);
--- a/js/src/vm/NativeObject-inl.h
+++ b/js/src/vm/NativeObject-inl.h
@@ -132,20 +132,23 @@ NativeObject::elementsRangeWriteBarrierP
}
inline void
NativeObject::copyDenseElements(uint32_t dstStart, const Value* src, uint32_t count)
{
MOZ_ASSERT(dstStart + count <= getDenseCapacity());
MOZ_ASSERT(!denseElementsAreCopyOnWrite());
MOZ_ASSERT(!denseElementsAreFrozen());
+ MOZ_ASSERT_IF(count > 0, src != nullptr);
#ifdef DEBUG
for (uint32_t i = 0; i < count; ++i)
checkStoredValue(src[i]);
#endif
+ if (count == 0)
+ return;
if (JS::shadow::Zone::asShadowZone(zone())->needsIncrementalBarrier()) {
uint32_t numShifted = getElementsHeader()->numShiftedElements();
for (uint32_t i = 0; i < count; ++i) {
elements_[dstStart + i].set(this, HeapSlot::Element,
dstStart + i + numShifted,
src[i]);
}
} else {
--- a/js/src/vm/NativeObject.cpp
+++ b/js/src/vm/NativeObject.cpp
@@ -2020,31 +2020,33 @@ js::NativeHasProperty(JSContext* cx, Han
// done can be true in exactly these unlikely-sounding cases:
// - We're looking up an element, and pobj is a TypedArray that
// doesn't have that many elements.
// - We're being called from a resolve hook to assign to the property
// being resolved.
// What they all have in common is we do not want to keep walking
// the prototype chain, and always claim that the property
// doesn't exist.
- RootedObject proto(cx, done ? nullptr : pobj->staticPrototype());
+ JSObject* proto = done ? nullptr : pobj->staticPrototype();
// Step 8.
if (!proto) {
*foundp = false;
return true;
}
// Step 7.a. If the prototype is also native, this step is a
// recursive tail call, and we don't need to go through all the
// plumbing of HasProperty; the top of the loop is where
// we're going to end up anyway. But if pobj is non-native,
// that optimization would be incorrect.
- if (!proto->isNative())
- return HasProperty(cx, proto, id, foundp);
+ if (!proto->isNative()) {
+ RootedObject protoRoot(cx, proto);
+ return HasProperty(cx, protoRoot, id, foundp);
+ }
pobj = &proto->as<NativeObject>();
}
}
/*** [[GetOwnPropertyDescriptor]] ****************************************************************/
--- a/js/src/vm/PIC.cpp
+++ b/js/src/vm/PIC.cpp
@@ -76,34 +76,16 @@ js::ForOfPIC::Chain::initialize(JSContex
arrayProtoIteratorSlot_ = iterShape->slot();
canonicalIteratorFunc_ = iterator;
arrayIteratorProtoShape_ = arrayIteratorProto->lastProperty();
arrayIteratorProtoNextSlot_ = nextShape->slot();
canonicalNextFunc_ = next;
return true;
}
-js::ForOfPIC::Stub*
-js::ForOfPIC::Chain::isArrayOptimized(ArrayObject* obj)
-{
- Stub* stub = getMatchingStub(obj);
- if (!stub)
- return nullptr;
-
- // Ensure that this is an otherwise optimizable array.
- if (!isOptimizableArray(obj))
- return nullptr;
-
- // Not yet enough! Ensure that the world as we know it remains sane.
- if (!isArrayStateStillSane())
- return nullptr;
-
- return stub;
-}
-
bool
js::ForOfPIC::Chain::tryOptimizeArray(JSContext* cx, HandleArrayObject array, bool* optimized)
{
MOZ_ASSERT(optimized);
*optimized = false;
if (!initialized_) {
@@ -122,71 +104,62 @@ js::ForOfPIC::Chain::tryOptimizeArray(JS
// If PIC is disabled, don't bother trying to optimize.
if (disabled_)
return true;
// By the time we get here, we should have a sane array state to work with.
MOZ_ASSERT(isArrayStateStillSane());
+ // Ensure array's prototype is the actual Array.prototype
+ if (array->staticPrototype() != arrayProto_)
+ return true;
+
// Check if stub already exists.
- ForOfPIC::Stub* stub = isArrayOptimized(&array->as<ArrayObject>());
- if (stub) {
+ if (hasMatchingStub(array)) {
*optimized = true;
return true;
}
+ // Ensure array doesn't define @@iterator directly.
+ if (array->lookup(cx, SYMBOL_TO_JSID(cx->wellKnownSymbols().iterator)))
+ return true;
+
// If the number of stubs is about to exceed the limit, throw away entire
// existing cache before adding new stubs. We shouldn't really have heavy
// churn on these.
if (numStubs() >= MAX_STUBS)
eraseChain();
- // Ensure array's prototype is the actual Array.prototype
- if (!isOptimizableArray(array))
- return true;
-
- // Ensure array doesn't define @@iterator directly.
- if (array->lookup(cx, SYMBOL_TO_JSID(cx->wellKnownSymbols().iterator)))
- return true;
-
// Good to optimize now, create stub to add.
RootedShape shape(cx, array->lastProperty());
- stub = cx->new_<Stub>(shape);
+ Stub* stub = cx->new_<Stub>(shape);
if (!stub)
return false;
// Add the stub.
addStub(stub);
*optimized = true;
return true;
}
-js::ForOfPIC::Stub*
-js::ForOfPIC::Chain::getMatchingStub(JSObject* obj)
+bool
+js::ForOfPIC::Chain::hasMatchingStub(ArrayObject* obj)
{
// Ensure PIC is initialized and not disabled.
- if (!initialized_ || disabled_)
- return nullptr;
+ MOZ_ASSERT(initialized_ && !disabled_);
// Check if there is a matching stub.
for (Stub* stub = stubs(); stub != nullptr; stub = stub->next()) {
- if (stub->shape() == obj->maybeShape())
- return stub;
+ if (stub->shape() == obj->shape())
+ return true;
}
- return nullptr;
-}
-
-bool
-js::ForOfPIC::Chain::isOptimizableArray(JSObject* obj)
-{
- MOZ_ASSERT(obj->is<ArrayObject>());
- return obj->staticPrototype() == arrayProto_;
+ return false;
}
bool
js::ForOfPIC::Chain::isArrayStateStillSane()
{
// Ensure that canonical Array.prototype has matching shape.
if (arrayProto_->lastProperty() != arrayProtoShape_)
return false;
--- a/js/src/vm/PIC.h
+++ b/js/src/vm/PIC.h
@@ -214,19 +214,16 @@ struct ForOfPIC
arrayIteratorProtoNextSlot_(-1),
initialized_(false),
disabled_(false)
{}
// Initialize the canonical iterator function.
bool initialize(JSContext* cx);
- // Check if a given array object is optimized by this PIC.
- Stub* isArrayOptimized(ArrayObject* obj);
-
// Try to optimize this chain for an object.
bool tryOptimizeArray(JSContext* cx, HandleArrayObject array, bool* optimized);
// Check if the global array-related objects have not been messed with
// in a way that would disable this PIC.
bool isArrayStateStillSane();
// Check if ArrayIterator.next is still optimizable.
@@ -234,21 +231,18 @@ struct ForOfPIC
return (arrayIteratorProto_->lastProperty() == arrayIteratorProtoShape_) &&
(arrayIteratorProto_->getSlot(arrayIteratorProtoNextSlot_) == canonicalNextFunc_);
}
void trace(JSTracer* trc);
void sweep(FreeOp* fop);
private:
- // Get a matching optimized stub for the given object.
- Stub* getMatchingStub(JSObject* obj);
-
- // Check if the given object is for-of optimizable with this PIC.
- bool isOptimizableArray(JSObject* obj);
+ // Check if a matching optimized stub for the given object exists.
+ bool hasMatchingStub(ArrayObject* obj);
// Reset the PIC and all info associated with it.
void reset(JSContext* cx);
// Erase the stub chain.
void eraseChain();
};
--- a/js/src/wasm/AsmJS.cpp
+++ b/js/src/wasm/AsmJS.cpp
@@ -1881,39 +1881,39 @@ class MOZ_STACK_CLASS ModuleValidator
bool atomicsPresent() const { return atomicsPresent_; }
uint32_t minMemoryLength() const { return mg_.minMemoryLength(); }
void initModuleFunctionName(PropertyName* name) {
MOZ_ASSERT(!moduleFunctionName_);
moduleFunctionName_ = name;
}
MOZ_MUST_USE bool initGlobalArgumentName(PropertyName* n) {
- MOZ_ASSERT(n->isTenured());
globalArgumentName_ = n;
if (n) {
+ MOZ_ASSERT(n->isTenured());
asmJSMetadata_->globalArgumentName = StringToNewUTF8CharsZ(cx_, *n);
if (!asmJSMetadata_->globalArgumentName)
return false;
}
return true;
}
MOZ_MUST_USE bool initImportArgumentName(PropertyName* n) {
- MOZ_ASSERT(n->isTenured());
importArgumentName_ = n;
if (n) {
+ MOZ_ASSERT(n->isTenured());
asmJSMetadata_->importArgumentName = StringToNewUTF8CharsZ(cx_, *n);
if (!asmJSMetadata_->importArgumentName)
return false;
}
return true;
}
MOZ_MUST_USE bool initBufferArgumentName(PropertyName* n) {
- MOZ_ASSERT(n->isTenured());
bufferArgumentName_ = n;
if (n) {
+ MOZ_ASSERT(n->isTenured());
asmJSMetadata_->bufferArgumentName = StringToNewUTF8CharsZ(cx_, *n);
if (!asmJSMetadata_->bufferArgumentName)
return false;
}
return true;
}
bool addGlobalVarInit(PropertyName* var, const NumLit& lit, Type type, bool isConst) {
MOZ_ASSERT(type.isGlobalVarType());
new file mode 100644
--- /dev/null
+++ b/layout/style/crashtests/1399006.html
@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<html>
+<script>
+window.onload=function(){
+ let n=document.getElementById('a');
+ n.parentNode.removeChild(n);
+ document.designMode='on';
+}
+</script>
+<wbr/>
+<script></script>
+<img space='-155.002502498'/>
+<blockquote style="display:ruby-text-container">
+<mark id='a'></mark>
+</blockquote>
+<video></video>
+<area/>
+<section></section>
+<img/>
+<noscript></noscript>
+<bdo></bdo>
+<select></select>
+<select></select>
+<option></option>
+<figure style="border-image:stretch url(data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs=) 27% fill / / 297.456633622ex"></figure>
+<wbr/>
+<pre></pre>
+<table>
+</html>
\ No newline at end of file
--- a/layout/style/crashtests/crashtests.list
+++ b/layout/style/crashtests/crashtests.list
@@ -213,18 +213,19 @@ load 1384232.html
load 1395725.html
load 1396041.html
load 1397363-1.html
load 1397439-1.html
load 1395719.html
load 1397091.html
load 1398479.html
load 1398581.html
+load 1399006.html
+load 1399546.html
load 1400035.html
-load 1399546.html
load 1400325.html
load 1400926.html
load 1401256.html
load 1402419.html
load 1401706.html
load 1400936-1.html
load 1400936-2.html
load 1402472.html
--- a/netwerk/cookie/CookieServiceChild.cpp
+++ b/netwerk/cookie/CookieServiceChild.cpp
@@ -173,17 +173,18 @@ CookieServiceChild::RecvAddCookie(const
aCookie.host(),
aCookie.path(),
aCookie.expiry(),
aCookie.lastAccessed(),
aCookie.creationTime(),
aCookie.isSession(),
aCookie.isSecure(),
false,
- aAttrs);
+ aAttrs,
+ aCookie.sameSite());
RecordDocumentCookie(cookie, aAttrs);
return IPC_OK();
}
mozilla::ipc::IPCResult
CookieServiceChild::RecvRemoveBatchDeletedCookies(nsTArray<CookieStruct>&& aCookiesList,
nsTArray<OriginAttributes>&& aAttrsList)
{
@@ -205,17 +206,18 @@ CookieServiceChild::RecvTrackCookiesLoad
aCookiesList[i].host(),
aCookiesList[i].path(),
aCookiesList[i].expiry(),
aCookiesList[i].lastAccessed(),
aCookiesList[i].creationTime(),
aCookiesList[i].isSession(),
aCookiesList[i].isSecure(),
false,
- aAttrs);
+ aAttrs,
+ aCookiesList[i].sameSite());
RecordDocumentCookie(cookie, aAttrs);
}
return IPC_OK();
}
void
CookieServiceChild::PrefChanged(nsIPrefBranch *aPrefBranch)
@@ -360,17 +362,18 @@ CookieServiceChild::SetCookieInternal(ns
aCookieAttributes.host,
aCookieAttributes.path,
aCookieAttributes.expiryTime,
currentTimeInUsec,
nsCookie::GenerateUniqueCreationTime(currentTimeInUsec),
aCookieAttributes.isSession,
aCookieAttributes.isSecure,
aCookieAttributes.isHttpOnly,
- aAttrs);
+ aAttrs,
+ aCookieAttributes.sameSite);
RecordDocumentCookie(cookie, aAttrs);
}
bool
CookieServiceChild::RequireThirdPartyCheck()
{
return mCookieBehavior == nsICookieService::BEHAVIOR_REJECT_FOREIGN ||
--- a/netwerk/cookie/CookieServiceParent.cpp
+++ b/netwerk/cookie/CookieServiceParent.cpp
@@ -86,16 +86,17 @@ GetInfoFromCookie(nsCookie *aCoo
aCookieStruct.value() = aCookie->Value();
aCookieStruct.host() = aCookie->Host();
aCookieStruct.path() = aCookie->Path();
aCookieStruct.expiry() = aCookie->Expiry();
aCookieStruct.lastAccessed() = aCookie->LastAccessed();
aCookieStruct.creationTime() = aCookie->CreationTime();
aCookieStruct.isSession() = aCookie->IsSession();
aCookieStruct.isSecure() = aCookie->IsSecure();
+ aCookieStruct.sameSite() = aCookie->SameSite();
}
void
CookieServiceParent::RemoveBatchDeletedCookies(nsIArray *aCookieList) {
uint32_t len = 0;
aCookieList->GetLength(&len);
OriginAttributes attrs;
CookieStruct cookieStruct;
@@ -181,16 +182,17 @@ CookieServiceParent::SerialializeCookieL
cookieStruct->value() = cookie->Value();
cookieStruct->host() = cookie->Host();
cookieStruct->path() = cookie->Path();
cookieStruct->expiry() = cookie->Expiry();
cookieStruct->lastAccessed() = cookie->LastAccessed();
cookieStruct->creationTime() = cookie->CreationTime();
cookieStruct->isSession() = cookie->IsSession();
cookieStruct->isSecure() = cookie->IsSecure();
+ cookieStruct->sameSite() = cookie->SameSite();
}
}
mozilla::ipc::IPCResult
CookieServiceParent::RecvPrepareCookieList(const URIParams &aHost,
const bool &aIsForeign,
const OriginAttributes &aAttrs)
{
--- a/netwerk/cookie/nsCookie.cpp
+++ b/netwerk/cookie/nsCookie.cpp
@@ -74,17 +74,18 @@ nsCookie::Create(const nsACString &aName
const nsACString &aHost,
const nsACString &aPath,
int64_t aExpiry,
int64_t aLastAccessed,
int64_t aCreationTime,
bool aIsSession,
bool aIsSecure,
bool aIsHttpOnly,
- const OriginAttributes& aOriginAttributes)
+ const OriginAttributes& aOriginAttributes,
+ int32_t aSameSite)
{
// Ensure mValue contains a valid UTF-8 sequence. Otherwise XPConnect will
// truncate the string after the first invalid octet.
RefPtr<nsUTF8ConverterService> converter = new nsUTF8ConverterService();
nsAutoCString aUTF8Value;
converter->ConvertStringToUTF8(aValue, "UTF-8", false, true, 1, aUTF8Value);
// find the required string buffer size, adding 4 for the terminating nulls
@@ -103,21 +104,26 @@ nsCookie::Create(const nsACString &aName
StrBlockCopy(aName, aUTF8Value, aHost, aPath,
name, value, host, path, end);
// If the creationTime given to us is higher than the running maximum, update
// our maximum.
if (aCreationTime > gLastCreationTime)
gLastCreationTime = aCreationTime;
+ // If aSameSite is not a sensible value, assume strict
+ if (aSameSite < 0 || aSameSite > nsICookie2::SAMESITE_STRICT) {
+ aSameSite = nsICookie2::SAMESITE_STRICT;
+ }
+
// construct the cookie. placement new, oh yeah!
return new (place) nsCookie(name, value, host, path, end,
aExpiry, aLastAccessed, aCreationTime,
aIsSession, aIsSecure, aIsHttpOnly,
- aOriginAttributes);
+ aOriginAttributes, aSameSite);
}
size_t
nsCookie::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
{
// There is no need to measure the sizes of the individual string
// members, since the strings are stored in-line with the nsCookie.
return aMallocSizeOf(this);
@@ -146,16 +152,17 @@ NS_IMETHODIMP nsCookie::GetExpiry(int64_
NS_IMETHODIMP nsCookie::GetIsSession(bool *aIsSession) { *aIsSession = IsSession(); return NS_OK; }
NS_IMETHODIMP nsCookie::GetIsDomain(bool *aIsDomain) { *aIsDomain = IsDomain(); return NS_OK; }
NS_IMETHODIMP nsCookie::GetIsSecure(bool *aIsSecure) { *aIsSecure = IsSecure(); return NS_OK; }
NS_IMETHODIMP nsCookie::GetIsHttpOnly(bool *aHttpOnly) { *aHttpOnly = IsHttpOnly(); return NS_OK; }
NS_IMETHODIMP nsCookie::GetStatus(nsCookieStatus *aStatus) { *aStatus = 0; return NS_OK; }
NS_IMETHODIMP nsCookie::GetPolicy(nsCookiePolicy *aPolicy) { *aPolicy = 0; return NS_OK; }
NS_IMETHODIMP nsCookie::GetCreationTime(int64_t *aCreation){ *aCreation = CreationTime(); return NS_OK; }
NS_IMETHODIMP nsCookie::GetLastAccessed(int64_t *aTime) { *aTime = LastAccessed(); return NS_OK; }
+NS_IMETHODIMP nsCookie::GetSameSite(int32_t *aSameSite) { *aSameSite = SameSite(); return NS_OK; }
NS_IMETHODIMP
nsCookie::GetOriginAttributes(JSContext *aCx, JS::MutableHandle<JS::Value> aVal)
{
if (NS_WARN_IF(!ToJSValue(aCx, mOriginAttributes, aVal))) {
return NS_ERROR_FAILURE;
}
return NS_OK;
--- a/netwerk/cookie/nsCookie.h
+++ b/netwerk/cookie/nsCookie.h
@@ -43,29 +43,31 @@ class nsCookie : public nsICookie2
const char *aPath,
const char *aEnd,
int64_t aExpiry,
int64_t aLastAccessed,
int64_t aCreationTime,
bool aIsSession,
bool aIsSecure,
bool aIsHttpOnly,
- const OriginAttributes& aOriginAttributes)
+ const OriginAttributes& aOriginAttributes,
+ int32_t aSameSite)
: mName(aName)
, mValue(aValue)
, mHost(aHost)
, mPath(aPath)
, mEnd(aEnd)
, mExpiry(aExpiry)
, mLastAccessed(aLastAccessed)
, mCreationTime(aCreationTime)
, mIsSession(aIsSession)
, mIsSecure(aIsSecure)
, mIsHttpOnly(aIsHttpOnly)
, mOriginAttributes(aOriginAttributes)
+ , mSameSite(aSameSite)
{
}
static int CookieStaleThreshold()
{
static bool initialized = false;
static int value = 60;
if (!initialized) {
@@ -87,17 +89,18 @@ class nsCookie : public nsICookie2
const nsACString &aHost,
const nsACString &aPath,
int64_t aExpiry,
int64_t aLastAccessed,
int64_t aCreationTime,
bool aIsSession,
bool aIsSecure,
bool aIsHttpOnly,
- const OriginAttributes& aOriginAttributes);
+ const OriginAttributes& aOriginAttributes,
+ int32_t aSameSite);
size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
// fast (inline, non-xpcom) getters
inline const nsDependentCString Name() const { return nsDependentCString(mName, mValue - 1); }
inline const nsDependentCString Value() const { return nsDependentCString(mValue, mHost - 1); }
inline const nsDependentCString Host() const { return nsDependentCString(mHost, mPath - 1); }
inline const nsDependentCString RawHost() const { return nsDependentCString(IsDomain() ? mHost + 1 : mHost, mPath - 1); }
@@ -105,16 +108,17 @@ class nsCookie : public nsICookie2
inline int64_t Expiry() const { return mExpiry; } // in seconds
inline int64_t LastAccessed() const { return mLastAccessed; } // in microseconds
inline int64_t CreationTime() const { return mCreationTime; } // in microseconds
inline bool IsSession() const { return mIsSession; }
inline bool IsDomain() const { return *mHost == '.'; }
inline bool IsSecure() const { return mIsSecure; }
inline bool IsHttpOnly() const { return mIsHttpOnly; }
inline const OriginAttributes& OriginAttributesRef() const { return mOriginAttributes; }
+ inline int32_t SameSite() const { return mSameSite; }
// setters
inline void SetExpiry(int64_t aExpiry) { mExpiry = aExpiry; }
inline void SetLastAccessed(int64_t aTime) { mLastAccessed = aTime; }
inline void SetIsSession(bool aIsSession) { mIsSession = aIsSession; }
// Set the creation time manually, overriding the monotonicity checks in
// Create(). Use with caution!
inline void SetCreationTime(int64_t aTime) { mCreationTime = aTime; }
@@ -139,16 +143,17 @@ class nsCookie : public nsICookie2
const char *mEnd;
int64_t mExpiry;
int64_t mLastAccessed;
int64_t mCreationTime;
bool mIsSession;
bool mIsSecure;
bool mIsHttpOnly;
mozilla::OriginAttributes mOriginAttributes;
+ int32_t mSameSite;
};
// Comparator class for sorting cookies before sending to a server.
class CompareCookiesForSending
{
public:
bool Equals(const nsCookie* aCookie1, const nsCookie* aCookie2) const
{
--- a/netwerk/cookie/nsCookieService.cpp
+++ b/netwerk/cookie/nsCookieService.cpp
@@ -75,31 +75,32 @@ using namespace mozilla::net;
static StaticRefPtr<nsCookieService> gCookieService;
// XXX_hack. See bug 178993.
// This is a hack to hide HttpOnly cookies from older browsers
#define HTTP_ONLY_PREFIX "#HttpOnly_"
#define COOKIES_FILE "cookies.sqlite"
-#define COOKIES_SCHEMA_VERSION 8
+#define COOKIES_SCHEMA_VERSION 9
// parameter indexes; see EnsureReadDomain, EnsureReadComplete and
// ReadCookieDBListener::HandleResult
#define IDX_NAME 0
#define IDX_VALUE 1
#define IDX_HOST 2
#define IDX_PATH 3
#define IDX_EXPIRY 4
#define IDX_LAST_ACCESSED 5
#define IDX_CREATION_TIME 6
#define IDX_SECURE 7
#define IDX_HTTPONLY 8
#define IDX_BASE_DOMAIN 9
#define IDX_ORIGIN_ATTRIBUTES 10
+#define IDX_SAME_SITE 11
#define TOPIC_CLEAR_ORIGIN_DATA "clear-origin-attributes-data"
static const int64_t kCookiePurgeAge =
int64_t(30 * 24 * 60 * 60) * PR_USEC_PER_SEC; // 30 days in microseconds
#define OLD_COOKIE_FILE_NAME "cookies.txt"
@@ -1386,16 +1387,26 @@ nsCookieService::TryInitDB(bool aRecreat
// Recreate our index.
rv = CreateIndex();
NS_ENSURE_SUCCESS(rv, RESULT_RETRY);
COOKIE_LOGSTRING(LogLevel::Debug,
("Upgraded database to schema version 8"));
}
+ MOZ_FALLTHROUGH;
+
+ case 8:
+ {
+ // Add the sameSite column to the table.
+ rv = mDefaultDBState->dbConn->ExecuteSimpleSQL(
+ NS_LITERAL_CSTRING("ALTER TABLE moz_cookies ADD sameSite INTEGER"));
+ COOKIE_LOGSTRING(LogLevel::Debug,
+ ("Upgraded database to schema version 9"));
+ }
// No more upgrades. Update the schema version.
rv = mDefaultDBState->dbConn->SetSchemaVersion(COOKIES_SCHEMA_VERSION);
NS_ENSURE_SUCCESS(rv, RESULT_RETRY);
MOZ_FALLTHROUGH;
case COOKIES_SCHEMA_VERSION:
break;
@@ -1433,17 +1444,18 @@ nsCookieService::TryInitDB(bool aRecreat
"name, "
"value, "
"host, "
"path, "
"expiry, "
"lastAccessed, "
"creationTime, "
"isSecure, "
- "isHttpOnly "
+ "isHttpOnly, "
+ "sameSite "
"FROM moz_cookies"), getter_AddRefs(stmt));
if (NS_SUCCEEDED(rv))
break;
// our columns aren't there - drop the table!
rv = mDefaultDBState->dbConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
"DROP TABLE moz_cookies"));
NS_ENSURE_SUCCESS(rv, RESULT_RETRY);
@@ -1474,29 +1486,31 @@ nsCookieService::TryInitDB(bool aRecreat
"name, "
"value, "
"host, "
"path, "
"expiry, "
"lastAccessed, "
"creationTime, "
"isSecure, "
- "isHttpOnly"
+ "isHttpOnly, "
+ "sameSite "
") VALUES ("
":baseDomain, "
":originAttributes, "
":name, "
":value, "
":host, "
":path, "
":expiry, "
":lastAccessed, "
":creationTime, "
":isSecure, "
- ":isHttpOnly"
+ ":isHttpOnly, "
+ ":sameSite"
")"),
getter_AddRefs(mDefaultDBState->stmtInsert));
NS_ENSURE_SUCCESS(rv, RESULT_RETRY);
rv = mDefaultDBState->dbConn->CreateAsyncStatement(NS_LITERAL_CSTRING(
"DELETE FROM moz_cookies "
"WHERE name = :name AND host = :host AND path = :path AND originAttributes = :originAttributes"),
getter_AddRefs(mDefaultDBState->stmtDelete));
@@ -1553,16 +1567,17 @@ nsCookieService::CreateTableWorker(const
"host TEXT, "
"path TEXT, "
"expiry INTEGER, "
"lastAccessed INTEGER, "
"creationTime INTEGER, "
"isSecure INTEGER, "
"isHttpOnly INTEGER, "
"inBrowserElement INTEGER DEFAULT 0, "
+ "sameSite INTEGER DEFAULT 0, "
"CONSTRAINT moz_uniqueid UNIQUE (name, host, path, originAttributes)"
")");
return mDefaultDBState->dbConn->ExecuteSimpleSQL(command);
}
// Sets the schema version and creates the moz_cookies table.
nsresult
nsCookieService::CreateTable()
@@ -2471,44 +2486,46 @@ nsCookieService::Add(const nsACString &a
const nsACString &aPath,
const nsACString &aName,
const nsACString &aValue,
bool aIsSecure,
bool aIsHttpOnly,
bool aIsSession,
int64_t aExpiry,
JS::HandleValue aOriginAttributes,
+ int32_t aSameSite,
JSContext* aCx,
uint8_t aArgc)
{
MOZ_ASSERT(aArgc == 0 || aArgc == 1);
OriginAttributes attrs;
nsresult rv = InitializeOriginAttributes(&attrs,
aOriginAttributes,
aCx,
aArgc,
u"nsICookieManager2.add()",
u"2");
NS_ENSURE_SUCCESS(rv, rv);
return AddNative(aHost, aPath, aName, aValue, aIsSecure, aIsHttpOnly,
- aIsSession, aExpiry, &attrs);
+ aIsSession, aExpiry, &attrs, aSameSite);
}
NS_IMETHODIMP_(nsresult)
nsCookieService::AddNative(const nsACString &aHost,
const nsACString &aPath,
const nsACString &aName,
const nsACString &aValue,
bool aIsSecure,
bool aIsHttpOnly,
bool aIsSession,
int64_t aExpiry,
- OriginAttributes* aOriginAttributes)
+ OriginAttributes* aOriginAttributes,
+ int32_t aSameSite)
{
if (NS_WARN_IF(!aOriginAttributes)) {
return NS_ERROR_FAILURE;
}
if (!mDBState) {
NS_WARNING("No DBState! Profile already closed?");
return NS_ERROR_NOT_AVAILABLE;
@@ -2534,17 +2551,18 @@ nsCookieService::AddNative(const nsACStr
RefPtr<nsCookie> cookie =
nsCookie::Create(aName, aValue, host, aPath,
aExpiry,
currentTimeInUsec,
nsCookie::GenerateUniqueCreationTime(currentTimeInUsec),
aIsSession,
aIsSecure,
aIsHttpOnly,
- key.mOriginAttributes);
+ key.mOriginAttributes,
+ aSameSite);
if (!cookie) {
return NS_ERROR_OUT_OF_MEMORY;
}
AddInternal(key, cookie, currentTimeInUsec, nullptr, nullptr, true);
return NS_OK;
}
@@ -2666,17 +2684,18 @@ nsCookieService::Read()
"host, "
"path, "
"expiry, "
"lastAccessed, "
"creationTime, "
"isSecure, "
"isHttpOnly, "
"baseDomain, "
- "originAttributes "
+ "originAttributes, "
+ "sameSite "
"FROM moz_cookies "
"WHERE baseDomain NOTNULL"), getter_AddRefs(stmtRead));
NS_ENSURE_SUCCESS(rv, RESULT_RETRY);
// Set up a statement to delete any rows with a nullptr 'baseDomain'
// column. This takes care of any cookies set by browsers that don't
// understand the 'baseDomain' column, where the database schema version
// is from one that does. (This would occur when downgrading.)
@@ -2727,26 +2746,28 @@ nsCookieService::GetCookieFromRow(T &aRo
rv = aRow->GetUTF8String(IDX_PATH, path);
NS_ASSERT_SUCCESS(rv);
int64_t expiry = aRow->AsInt64(IDX_EXPIRY);
int64_t lastAccessed = aRow->AsInt64(IDX_LAST_ACCESSED);
int64_t creationTime = aRow->AsInt64(IDX_CREATION_TIME);
bool isSecure = 0 != aRow->AsInt32(IDX_SECURE);
bool isHttpOnly = 0 != aRow->AsInt32(IDX_HTTPONLY);
+ int32_t sameSite = aRow->AsInt32(IDX_SAME_SITE);
// Create a new nsCookie and assign the data.
return nsCookie::Create(name, value, host, path,
expiry,
lastAccessed,
creationTime,
false,
isSecure,
isHttpOnly,
- aOriginAttributes);
+ aOriginAttributes,
+ sameSite);
}
void
nsCookieService::AsyncReadComplete()
{
// We may be in the private browsing DB state, with a pending read on the
// default DB state. (This would occur if we started up in private browsing
// mode.) As long as we do all our operations on the default state, we're OK.
@@ -2845,17 +2866,20 @@ nsCookieService::EnsureReadDomain(const
"name, "
"value, "
"host, "
"path, "
"expiry, "
"lastAccessed, "
"creationTime, "
"isSecure, "
- "isHttpOnly "
+ "isHttpOnly, "
+ "baseDomain, "
+ "originAttributes, "
+ "sameSite "
"FROM moz_cookies "
"WHERE baseDomain = :baseDomain "
" AND originAttributes = :originAttributes"),
getter_AddRefs(mDefaultDBState->stmtReadDomain));
if (NS_FAILED(rv)) {
// Recreate the database.
COOKIE_LOGSTRING(LogLevel::Debug,
@@ -2942,17 +2966,18 @@ nsCookieService::EnsureReadComplete()
"host, "
"path, "
"expiry, "
"lastAccessed, "
"creationTime, "
"isSecure, "
"isHttpOnly, "
"baseDomain, "
- "originAttributes "
+ "originAttributes, "
+ "sameSite "
"FROM moz_cookies "
"WHERE baseDomain NOTNULL"), getter_AddRefs(stmt));
if (NS_FAILED(rv)) {
// Recreate the database.
COOKIE_LOGSTRING(LogLevel::Debug,
("EnsureReadComplete(): corruption detected when creating statement "
"with rv 0x%" PRIx32, static_cast<uint32_t>(rv)));
@@ -3146,17 +3171,18 @@ nsCookieService::ImportCookies(nsIFile *
host,
Substring(buffer, pathIndex, secureIndex - pathIndex - 1),
expires,
lastAccessedCounter,
nsCookie::GenerateUniqueCreationTime(currentTimeInUsec),
false,
Substring(buffer, secureIndex, expiresIndex - secureIndex - 1).EqualsLiteral(kTrue),
isHttpOnly,
- key.mOriginAttributes);
+ key.mOriginAttributes,
+ nsICookie2::SAMESITE_UNSET);
if (!newCookie) {
return NS_ERROR_OUT_OF_MEMORY;
}
// trick: preserve the most-recently-used cookie ordering,
// by successively decrementing the lastAccessed time
lastAccessedCounter--;
@@ -3596,17 +3622,18 @@ nsCookieService::SetCookieInternal(nsIUR
cookieAttributes.host,
cookieAttributes.path,
cookieAttributes.expiryTime,
currentTimeInUsec,
nsCookie::GenerateUniqueCreationTime(currentTimeInUsec),
cookieAttributes.isSession,
cookieAttributes.isSecure,
cookieAttributes.isHttpOnly,
- aKey.mOriginAttributes);
+ aKey.mOriginAttributes,
+ cookieAttributes.sameSite);
if (!cookie)
return newCookie;
// check permissions from site permission list, or ask the user,
// to determine if we can set the cookie
if (mPermissionService) {
bool permission;
mPermissionService->CanSetCookie(aHostURI,
@@ -3988,24 +4015,27 @@ nsCookieService::ParseAttributes(nsDepen
nsCookieAttributes &aCookieAttributes)
{
static const char kPath[] = "path";
static const char kDomain[] = "domain";
static const char kExpires[] = "expires";
static const char kMaxage[] = "max-age";
static const char kSecure[] = "secure";
static const char kHttpOnly[] = "httponly";
+ static const char kSameSite[] = "samesite";
+ static const char kSameSiteLax[] = "lax";
nsACString::const_char_iterator tempBegin, tempEnd;
nsACString::const_char_iterator cookieStart, cookieEnd;
aCookieHeader.BeginReading(cookieStart);
aCookieHeader.EndReading(cookieEnd);
aCookieAttributes.isSecure = false;
aCookieAttributes.isHttpOnly = false;
+ aCookieAttributes.sameSite = nsICookie2::SAMESITE_UNSET;
nsDependentCSubstring tokenString(cookieStart, cookieStart);
nsDependentCSubstring tokenValue (cookieStart, cookieStart);
bool newCookie, equalsFound;
// extract cookie <NAME> & <VALUE> (first attribute), and copy the strings.
// if we find multiple cookies, return for processing
// note: if there's no '=', we assume token is <VALUE>. this is required by
@@ -4044,16 +4074,24 @@ nsCookieService::ParseAttributes(nsDepen
// ignore any tokenValue for isSecure; just set the boolean
else if (tokenString.LowerCaseEqualsLiteral(kSecure))
aCookieAttributes.isSecure = true;
// ignore any tokenValue for isHttpOnly (see bug 178993);
// just set the boolean
else if (tokenString.LowerCaseEqualsLiteral(kHttpOnly))
aCookieAttributes.isHttpOnly = true;
+
+ else if (tokenString.LowerCaseEqualsLiteral(kSameSite)) {
+ if (tokenValue.LowerCaseEqualsLiteral(kSameSiteLax)) {
+ aCookieAttributes.sameSite = nsICookie2::SAMESITE_LAX;
+ } else {
+ aCookieAttributes.sameSite = nsICookie2::SAMESITE_STRICT;
+ }
+ }
}
// rebind aCookieHeader, in case we need to process another cookie
aCookieHeader.Rebind(cookieStart, cookieEnd);
return newCookie;
}
/******************************************************************************
@@ -5208,16 +5246,20 @@ bindCookieParameters(mozIStorageBindingP
rv = params->BindInt32ByName(NS_LITERAL_CSTRING("isSecure"),
aCookie->IsSecure());
NS_ASSERT_SUCCESS(rv);
rv = params->BindInt32ByName(NS_LITERAL_CSTRING("isHttpOnly"),
aCookie->IsHttpOnly());
NS_ASSERT_SUCCESS(rv);
+ rv = params->BindInt32ByName(NS_LITERAL_CSTRING("sameSite"),
+ aCookie->SameSite());
+ NS_ASSERT_SUCCESS(rv);
+
// Bind the params to the array.
rv = aParamsArray->AddParams(params);
NS_ASSERT_SUCCESS(rv);
}
void
nsCookieService::UpdateCookieOldestTime(DBState* aDBState,
nsCookie* aCookie)
--- a/netwerk/cookie/nsCookieService.h
+++ b/netwerk/cookie/nsCookieService.h
@@ -190,16 +190,17 @@ struct nsCookieAttributes
nsAutoCString host;
nsAutoCString path;
nsAutoCString expires;
nsAutoCString maxage;
int64_t expiryTime;
bool isSession;
bool isSecure;
bool isHttpOnly;
+ int8_t sameSite;
};
class nsCookieService final : public nsICookieService
, public nsICookieManager2
, public nsIObserver
, public nsSupportsWeakReference
, public nsIMemoryReporter
{
--- a/netwerk/cookie/nsICookie2.idl
+++ b/netwerk/cookie/nsICookie2.idl
@@ -6,20 +6,23 @@
#include "nsICookie.idl"
/**
* Main cookie object interface for use by consumers:
* extends nsICookie, a frozen interface for external
* access of cookie objects
*/
-[scriptable, uuid(05c420e5-03d0-4c7b-a605-df7ebe5ca326)]
+[scriptable, uuid(be205dae-4f4c-11e6-80ba-ea5cd310c1a8)]
interface nsICookie2 : nsICookie
{
+ const uint32_t SAMESITE_UNSET = 0;
+ const uint32_t SAMESITE_LAX = 1;
+ const uint32_t SAMESITE_STRICT = 2;
/**
* the host (possibly fully qualified) of the cookie,
* without a leading dot to represent if it is a
* domain cookie.
*/
readonly attribute AUTF8String rawHost;
@@ -55,9 +58,20 @@ interface nsICookie2 : nsICookie
* the last time the cookie was accessed (i.e. created,
* modified, or read by the server), in microseconds
* since midnight (00:00:00), January 1, 1970 UTC.
*
* note that this time may be approximate.
*/
readonly attribute int64_t lastAccessed;
+ /**
+ * the sameSite attribute; this controls the cookie behavior for cross-site
+ * requests as per
+ * https://tools.ietf.org/html/draft-west-first-party-cookies-07
+ *
+ * This should be one of:
+ * - SAMESITE_UNSET - the SameSite attribute is not present
+ * - SAMESITE_LAX - the SameSite attribute is present, but not strict
+ * - SAMESITE_STRICT - the SameSite attribute is present and strict
+ */
+ readonly attribute int32_t sameSite;
};
--- a/netwerk/cookie/nsICookieManager2.idl
+++ b/netwerk/cookie/nsICookieManager2.idl
@@ -41,40 +41,46 @@ interface nsICookieManager2 : nsICookieM
* modified by, an http connection.
* @param aIsSession
* true if the cookie should exist for the current session only.
* see aExpiry.
* @param aExpiry
* expiration date, in seconds since midnight (00:00:00), January 1,
* 1970 UTC. note that expiry time will also be honored for session cookies;
* in this way, the more restrictive of the two will take effect.
- * @param aOriginAttributes The originAttributes of this cookie. This
- * attribute is optional to avoid breaking add-ons.
+ * @param aOriginAttributes
+ * the originAttributes of this cookie. This attribute is optional to
+ * avoid breaking add-ons.
+ * @param aSameSite
+ * the SameSite attribute. This attribute is optional to avoid breaking
+ * addons
*/
[implicit_jscontext, optional_argc]
void add(in AUTF8String aHost,
in AUTF8String aPath,
in ACString aName,
in ACString aValue,
in boolean aIsSecure,
in boolean aIsHttpOnly,
in boolean aIsSession,
in int64_t aExpiry,
- [optional] in jsval aOriginAttributes);
+ [optional] in jsval aOriginAttributes,
+ [optional] in int32_t aSameSite);
[notxpcom]
nsresult addNative(in AUTF8String aHost,
in AUTF8String aPath,
in ACString aName,
in ACString aValue,
in boolean aIsSecure,
in boolean aIsHttpOnly,
in boolean aIsSession,
in int64_t aExpiry,
- in OriginAttributesPtr aOriginAttributes);
+ in OriginAttributesPtr aOriginAttributes,
+ in int32_t aSameSite);
/**
* Find whether a given cookie already exists.
*
* @param aCookie
* the cookie to look for
* @param aOriginAttributes
* nsICookie2 contains an originAttributes but if nsICookie2 is
--- a/netwerk/ipc/NeckoChannelParams.ipdlh
+++ b/netwerk/ipc/NeckoChannelParams.ipdlh
@@ -207,12 +207,13 @@ struct CookieStruct
nsCString value;
nsCString host;
nsCString path;
int64_t expiry;
int64_t lastAccessed;
int64_t creationTime;
bool isSession;
bool isSecure;
+ int8_t sameSite;
};
} // namespace ipc
} // namespace mozilla
--- a/netwerk/test/TestCookie.cpp
+++ b/netwerk/test/TestCookie.cpp
@@ -629,35 +629,38 @@ TEST(TestCookie,TestCookieMain)
EXPECT_TRUE(NS_SUCCEEDED(cookieMgr2->AddNative(NS_LITERAL_CSTRING("cookiemgr.test"), // domain
NS_LITERAL_CSTRING("/foo"), // path
NS_LITERAL_CSTRING("test1"), // name
NS_LITERAL_CSTRING("yes"), // value
false, // is secure
false, // is httponly
true, // is session
INT64_MAX, // expiry time
- &attrs))); // originAttributes
+ &attrs, // originAttributes
+ nsICookie2::SAMESITE_UNSET)));
EXPECT_TRUE(NS_SUCCEEDED(cookieMgr2->AddNative(NS_LITERAL_CSTRING("cookiemgr.test"), // domain
NS_LITERAL_CSTRING("/foo"), // path
NS_LITERAL_CSTRING("test2"), // name
NS_LITERAL_CSTRING("yes"), // value
false, // is secure
true, // is httponly
true, // is session
PR_Now() / PR_USEC_PER_SEC + 2, // expiry time
- &attrs))); // originAttributes
+ &attrs, // originAttributes
+ nsICookie2::SAMESITE_UNSET)));
EXPECT_TRUE(NS_SUCCEEDED(cookieMgr2->AddNative(NS_LITERAL_CSTRING("new.domain"), // domain
NS_LITERAL_CSTRING("/rabbit"), // path
NS_LITERAL_CSTRING("test3"), // name
NS_LITERAL_CSTRING("yes"), // value
false, // is secure
false, // is httponly
true, // is session
INT64_MAX, // expiry time
- &attrs))); // originAttributes
+ &attrs, // originAttributes
+ nsICookie2::SAMESITE_UNSET)));
// confirm using enumerator
nsCOMPtr<nsISimpleEnumerator> enumerator;
EXPECT_TRUE(NS_SUCCEEDED(cookieMgr->GetEnumerator(getter_AddRefs(enumerator))));
int32_t i = 0;
bool more;
nsCOMPtr<nsICookie2> expiredCookie, newDomainCookie;
while (NS_SUCCEEDED(enumerator->HasMoreElements(&more)) && more) {
nsCOMPtr<nsISupports> cookie;
@@ -701,17 +704,18 @@ TEST(TestCookie,TestCookieMain)
EXPECT_TRUE(NS_SUCCEEDED(cookieMgr2->AddNative(NS_LITERAL_CSTRING("new.domain"), // domain
NS_LITERAL_CSTRING("/rabbit"), // path
NS_LITERAL_CSTRING("test3"), // name
NS_LITERAL_CSTRING("yes"), // value
false, // is secure
false, // is httponly
true, // is session
INT64_MIN, // expiry time
- &attrs))); // originAttributes
+ &attrs, // originAttributes
+ nsICookie2::SAMESITE_UNSET)));
EXPECT_TRUE(NS_SUCCEEDED(cookieMgr2->CookieExistsNative(newDomainCookie, &attrs, &found)));
EXPECT_FALSE(found);
// sleep four seconds, to make sure the second cookie has expired
PR_Sleep(4 * PR_TicksPerSecond());
// check that both CountCookiesFromHost() and CookieExistsNative() count the
// expired cookie
EXPECT_TRUE(NS_SUCCEEDED(cookieMgr2->CountCookiesFromHost(NS_LITERAL_CSTRING("cookiemgr.test"), &hostCookies)));
EXPECT_EQ(hostCookies, 2u);
@@ -759,15 +763,60 @@ TEST(TestCookie,TestCookieMain)
name += NS_LITERAL_CSTRING("; secure");
SetACookie(cookieService, "https://creation.ordering.tests/", nullptr, name.get(), nullptr);
} else {
// non-security cookies will be removed beside the latest cookie that be created.
SetACookie(cookieService, "http://creation.ordering.tests/", nullptr, name.get(), nullptr);
}
}
GetACookie(cookieService, "http://creation.ordering.tests/", nullptr, getter_Copies(cookie));
+
EXPECT_TRUE(CheckResult(cookie.get(), MUST_BE_NULL));
+
+ // *** SameSite attribute - parsing and cookie storage tests
+ // Clear the cookies
+ EXPECT_TRUE(NS_SUCCEEDED(cookieMgr->RemoveAll()));
+
+ // Set cookies with various incantations of the samesite attribute:
+ // No same site attribute present
+ SetACookie(cookieService, "http://samesite.test", nullptr, "unset=yes", nullptr);
+ // samesite attribute present but with no value
+ SetACookie(cookieService, "http://samesite.test", nullptr, "unspecified=yes; samesite", nullptr);
+ // samesite=strict
+ SetACookie(cookieService, "http://samesite.test", nullptr, "strict=yes; samesite=strict", nullptr);
+ // samesite=lax
+ SetACookie(cookieService, "http://samesite.test", nullptr, "lax=yes; samesite=lax", nullptr);
+
+ EXPECT_TRUE(NS_SUCCEEDED(cookieMgr->GetEnumerator(getter_AddRefs(enumerator))));
+ i = 0;
+
+ // check the cookies for the required samesite value
+ while (NS_SUCCEEDED(enumerator->HasMoreElements(&more)) && more) {
+ nsCOMPtr<nsISupports> cookie;
+ if (NS_FAILED(enumerator->GetNext(getter_AddRefs(cookie)))) break;
+ ++i;
+
+ // keep tabs on the second and third cookies, so we can check them later
+ nsCOMPtr<nsICookie2> cookie2(do_QueryInterface(cookie));
+ if (!cookie2) break;
+ nsAutoCString name;
+ cookie2->GetName(name);
+ int32_t sameSiteAttr;
+ cookie2->GetSameSite(&sameSiteAttr);
+ if (name.EqualsLiteral("unset")) {
+ EXPECT_TRUE(sameSiteAttr == nsICookie2::SAMESITE_UNSET);
+ } else if (name.EqualsLiteral("unspecified")) {
+ EXPECT_TRUE(sameSiteAttr == nsICookie2::SAMESITE_STRICT);
+ } else if (name.EqualsLiteral("strict")) {
+ EXPECT_TRUE(sameSiteAttr == nsICookie2::SAMESITE_STRICT);
+ } else if (name.EqualsLiteral("lax")) {
+ EXPECT_TRUE(sameSiteAttr == nsICookie2::SAMESITE_LAX);
+ }
+ }
+
+ EXPECT_TRUE(i == 4);
+
// XXX the following are placeholders: add these tests please!
// *** "noncompliant cookie" tests
// *** IP address tests
// *** speed tests
}
--- a/parser/htmlparser/nsElementTable.cpp
+++ b/parser/htmlparser/nsElementTable.cpp
@@ -1,244 +1,206 @@
/* -*- 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 "nsElementTable.h"
-static const int kNone= 0x0;
-
-static const int kHTMLContent = 0x0001; // HEAD, (FRAMESET | BODY)
-static const int kHeadContent = 0x0002; // Elements that *must* be in the head.
-static const int kHeadMisc = 0x0004; // Elements that *can* be in the head.
-
-static const int kSpecial = 0x0008; // A, IMG, APPLET, OBJECT, FONT, BASEFONT, BR, SCRIPT,
- // MAP, Q, SUB, SUP, SPAN, BDO, IFRAME
-
-static const int kFormControl = 0x0010; // INPUT SELECT TEXTAREA LABEL BUTTON
-static const int kPreformatted = 0x0020; // PRE
-static const int kPreExclusion = 0x0040; // IMG, OBJECT, APPLET, BIG, SMALL, SUB, SUP, FONT, BASEFONT
-static const int kFontStyle = 0x0080; // TT, I, B, U, S, STRIKE, BIG, SMALL
-static const int kPhrase = 0x0100; // EM, STRONG, DFN, CODE, SAMP, KBD, VAR, CITE, ABBR, ACRONYM
-static const int kHeading = 0x0200; // H1..H6
-static const int kBlockMisc = 0x0400; // OBJECT, SCRIPT
-static const int kBlock = 0x0800; // ADDRESS, BLOCKQUOTE, CENTER, DIV, DL, FIELDSET, FORM,
- // ISINDEX, HR, NOSCRIPT, NOFRAMES, P, TABLE
-static const int kList = 0x1000; // UL, OL, DIR, MENU
-static const int kPCDATA = 0x2000; // plain text and entities...
-static const int kSelf = 0x4000; // whatever THIS tag is...
-static const int kExtensions = 0x8000; // BGSOUND, WBR, NOBR
-static const int kTable = 0x10000;// TR,TD,THEAD,TBODY,TFOOT,CAPTION,TH
-static const int kDLChild = 0x20000;// DL, DT
-static const int kCDATA = 0x40000;// just plain text...
-
-static const int kInlineEntity = (kPCDATA|kFontStyle|kPhrase|kSpecial|kFormControl|kExtensions); // #PCDATA, %fontstyle, %phrase, %special, %formctrl
-static const int kBlockEntity = (kHeading|kList|kPreformatted|kBlock); // %heading, %list, %preformatted, %block
-static const int kFlowEntity = (kBlockEntity|kInlineEntity); // %blockentity, %inlineentity
-static const int kAllTags = 0xffffff;
-
-// Is aTest a member of aBitset?
-static bool
-TestBits(int32_t aBitset, int32_t aTest)
-{
- if (aTest) {
- int32_t result = aBitset & aTest;
- return result == aTest;
- }
- return false;
-}
-
struct HTMLElement
{
- bool IsMemberOf(int32_t aBitset) const
- {
- return TestBits(aBitset, mParentBits);
- }
-
#ifdef DEBUG
nsHTMLTag mTagID;
#endif
- int mParentBits; // defines groups that can contain this element
- bool mLeaf;
+ bool mIsBlock;
+ bool mIsContainer;
};
#ifdef DEBUG
-#define ELEM(tag, parent, leaf) { eHTMLTag_##tag, parent, leaf },
+#define ELEM(tag, block, container) { eHTMLTag_##tag, block, container },
#else
-#define ELEM(tag, parent, leaf) { parent, leaf },
+#define ELEM(tag, block, container) { block, container },
#endif
+#define ____ false // This makes the table easier to read.
+
+// Note that the mIsBlock field disagrees with
+// https://developer.mozilla.org/en-US/docs/Web/HTML/Block-level_elements for
+// the following elements: center, details, dialog, dir, dt, figcaption,
+// listing, menu, multicol, noscript, output, summary, tfoot, video.
+//
+// mrbkap thinks that the field values were pulled from the old HTML4 DTD and
+// then got modified in mostly random ways to make the old parser's behavior
+// compatible with the web. So it might make sense to change the mIsBlock
+// values for the abovementioned tags at some point.
+//
static const HTMLElement gHTMLElements[] = {
- ELEM(unknown, kNone, true)
- ELEM(a, kSpecial, false)
- ELEM(abbr, kPhrase, false)
- ELEM(acronym, kPhrase, false)
- ELEM(address, kBlock, false)
- ELEM(applet, kSpecial, false)
- ELEM(area, kNone, true)
- ELEM(article, kBlock, false)
- ELEM(aside, kBlock, false)
- ELEM(audio, kSpecial, false)
- ELEM(b, kFontStyle, false)
- ELEM(base, kHeadContent, true)
- ELEM(basefont, kSpecial, true)
- ELEM(bdo, kSpecial, false)
- ELEM(bgsound, (kFlowEntity|kHeadMisc), true)
- ELEM(big, kFontStyle, false)
- ELEM(blockquote, kBlock, false)
- ELEM(body, kHTMLContent, false)
- ELEM(br, kSpecial, true)
- ELEM(button, kFormControl, false)
- ELEM(canvas, kSpecial, false)
- ELEM(caption, kNone, false)
- ELEM(center, kBlock, false)
- ELEM(cite, kPhrase, false)
- ELEM(code, kPhrase, false)
- ELEM(col, kNone, true)
- ELEM(colgroup, kNone, false)
- ELEM(content, kNone, false)
- ELEM(data, kPhrase, false)
- ELEM(datalist, kSpecial, false)
- ELEM(dd, kInlineEntity, false)
- ELEM(del, kFlowEntity, false)
- ELEM(details, kBlock, false)
- ELEM(dfn, kPhrase, false)
- ELEM(dialog, kBlock, false)
- ELEM(dir, kList, false)
- ELEM(div, kBlock, false)
- ELEM(dl, kBlock, false)
- ELEM(dt, kInlineEntity, false)
- ELEM(em, kPhrase, false)
- ELEM(embed, kSpecial, true)
- ELEM(fieldset, kBlock, false)
- ELEM(figcaption, kPhrase, false)
- ELEM(figure, kBlock, false)
- ELEM(font, kFontStyle, false)
- ELEM(footer, kBlock, false)
- ELEM(form, kBlock, false)
- ELEM(frame, kNone, true)
- ELEM(frameset, kHTMLContent, false)
- ELEM(h1, kHeading, false)
- ELEM(h2, kHeading, false)
- ELEM(h3, kHeading, false)
- ELEM(h4, kHeading, false)
- ELEM(h5, kHeading, false)
- ELEM(h6, kHeading, false)
- ELEM(head, kHTMLContent, false)
- ELEM(header, kBlock, false)
- ELEM(hgroup, kBlock, false)
- ELEM(hr, kBlock, true)
- ELEM(html, kNone, false)
- ELEM(i, kFontStyle, false)
- ELEM(iframe, kSpecial, false)
- ELEM(image, kSpecial, true)
- ELEM(img, kSpecial, true)
- ELEM(input, kFormControl, true)
- ELEM(ins, kFlowEntity, false)
- ELEM(kbd, kPhrase, false)
- ELEM(keygen, kFlowEntity, true)
- ELEM(label, kFormControl, false)
- ELEM(legend, kNone, false)
- ELEM(li, kBlockEntity, false)
- ELEM(link, kAllTags - kHeadContent, true)
- ELEM(listing, kPreformatted, false)
- ELEM(main, kBlock, false)
- ELEM(map, kSpecial, false)
- ELEM(mark, kSpecial, false)
- ELEM(marquee, kSpecial, false)
- ELEM(menu, kList, false)
- ELEM(menuitem, kFlowEntity, false)
- ELEM(meta, kHeadContent, true)
- ELEM(meter, kFormControl, false)
- ELEM(multicol, kBlock, false)
- ELEM(nav, kBlock, false)
- ELEM(nobr, kExtensions, false)
- ELEM(noembed, kFlowEntity, false)
- ELEM(noframes, kFlowEntity, false)
- ELEM(noscript, kFlowEntity|kHeadMisc, false)
- ELEM(object, kSpecial, false)
- ELEM(ol, kList, false)
- ELEM(optgroup, kNone, false)
- ELEM(option, kNone, false)
- ELEM(output, kSpecial, false)
- ELEM(p, kBlock, false)
- ELEM(param, kSpecial, true)
- ELEM(picture, kSpecial, false)
- ELEM(plaintext, kExtensions, false)
- ELEM(pre, kBlock|kPreformatted, false)
- ELEM(progress, kFormControl, false)
- ELEM(q, kSpecial, false)
- ELEM(rb, kPhrase, false)
- ELEM(rp, kPhrase, false)
- ELEM(rt, kPhrase, false)
- ELEM(rtc, kPhrase, false)
- ELEM(ruby, kPhrase, false)
- ELEM(s, kFontStyle, false)
- ELEM(samp, kPhrase, false)
- ELEM(script, (kSpecial|kHeadContent), false)
- ELEM(section, kBlock, false)
- ELEM(select, kFormControl, false)
- ELEM(shadow, kFlowEntity, false)
- ELEM(small, kFontStyle, false)
- ELEM(source, kSpecial, true)
- ELEM(span, kSpecial, false)
- ELEM(strike, kFontStyle, false)
- ELEM(strong, kPhrase, false)
- ELEM(style, kAllTags - kHeadContent, false)
- ELEM(sub, kSpecial, false)
- ELEM(summary, kBlock, false)
- ELEM(sup, kSpecial, false)
- ELEM(table, kBlock, false)
- ELEM(tbody, kNone, false)
- ELEM(td, kNone, false)
- ELEM(textarea, kFormControl, false)
- ELEM(tfoot, kNone, false)
- ELEM(th, kNone, false)
- ELEM(thead, kNone, false)
- ELEM(template, kNone, false)
- ELEM(time, kPhrase, false)
- ELEM(title, kHeadContent, false)
- ELEM(tr, kNone, false)
- ELEM(track, kSpecial, true)
- ELEM(tt, kFontStyle, false)
- ELEM(u, kFontStyle, false)
- ELEM(ul, kList, false)
- ELEM(var, kPhrase, false)
- ELEM(video, kSpecial, false)
- ELEM(wbr, kExtensions, true)
- ELEM(xmp, kInlineEntity|kPreformatted, false)
- ELEM(text, kFlowEntity, true)
- ELEM(whitespace, kFlowEntity|kHeadMisc, true)
- ELEM(newline, kFlowEntity|kHeadMisc, true)
- ELEM(comment, kFlowEntity|kHeadMisc, false)
- ELEM(entity, kFlowEntity, false)
- ELEM(doctypeDecl, kFlowEntity, false)
- ELEM(markupDecl, kFlowEntity, false)
- ELEM(instruction, kFlowEntity, false)
- ELEM(userdefined, (kFlowEntity|kHeadMisc), false)
+ ELEM(unknown, ____, ____)
+ ELEM(a, ____, true)
+ ELEM(abbr, ____, true)
+ ELEM(acronym, ____, true)
+ ELEM(address, true, true)
+ ELEM(applet, ____, true)
+ ELEM(area, ____, ____)
+ ELEM(article, true, true)
+ ELEM(aside, true, true)
+ ELEM(audio, ____, true)
+ ELEM(b, ____, true)
+ ELEM(base, ____, ____)
+ ELEM(basefont, ____, ____)
+ ELEM(bdo, ____, true)
+ ELEM(bgsound, ____, ____)
+ ELEM(big, ____, true)
+ ELEM(blockquote, true, true)
+ ELEM(body, ____, true)
+ ELEM(br, ____, ____)
+ ELEM(button, ____, true)
+ ELEM(canvas, ____, true)
+ ELEM(caption, ____, true)
+ ELEM(center, true, true)
+ ELEM(cite, ____, true)
+ ELEM(code, ____, true)
+ ELEM(col, ____, ____)
+ ELEM(colgroup, ____, true)
+ ELEM(content, ____, true)
+ ELEM(data, ____, true)
+ ELEM(datalist, ____, true)
+ ELEM(dd, ____, true)
+ ELEM(del, ____, true)
+ ELEM(details, true, true)
+ ELEM(dfn, ____, true)
+ ELEM(dialog, true, true)
+ ELEM(dir, true, true)
+ ELEM(div, true, true)
+ ELEM(dl, true, true)
+ ELEM(dt, ____, true)
+ ELEM(em, ____, true)
+ ELEM(embed, ____, ____)
+ ELEM(fieldset, true, true)
+ ELEM(figcaption, ____, true)
+ ELEM(figure, true, true)
+ ELEM(font, ____, true)
+ ELEM(footer, true, true)
+ ELEM(form, true, true)
+ ELEM(frame, ____, ____)
+ ELEM(frameset, ____, true)
+ ELEM(h1, true, true)
+ ELEM(h2, true, true)
+ ELEM(h3, true, true)
+ ELEM(h4, true, true)
+ ELEM(h5, true, true)
+ ELEM(h6, true, true)
+ ELEM(head, ____, true)
+ ELEM(header, true, true)
+ ELEM(hgroup, true, true)
+ ELEM(hr, true, ____)
+ ELEM(html, ____, true)
+ ELEM(i, ____, true)
+ ELEM(iframe, ____, true)
+ ELEM(image, ____, ____)
+ ELEM(img, ____, ____)
+ ELEM(input, ____, ____)
+ ELEM(ins, ____, true)
+ ELEM(kbd, ____, true)
+ ELEM(keygen, ____, ____)
+ ELEM(label, ____, true)
+ ELEM(legend, ____, true)
+ ELEM(li, true, true)
+ ELEM(link, ____, ____)
+ ELEM(listing, true, true)
+ ELEM(main, true, true)
+ ELEM(map, ____, true)
+ ELEM(mark, ____, true)
+ ELEM(marquee, ____, true)
+ ELEM(menu, true, true)
+ ELEM(menuitem, ____, true)
+ ELEM(meta, ____, ____)
+ ELEM(meter, ____, true)
+ ELEM(multicol, true, true)
+ ELEM(nav, true, true)
+ ELEM(nobr, ____, true)
+ ELEM(noembed, ____, true)
+ ELEM(noframes, ____, true)
+ ELEM(noscript, ____, true)
+ ELEM(object, ____, true)
+ ELEM(ol, true, true)
+ ELEM(optgroup, ____, true)
+ ELEM(option, ____, true)
+ ELEM(output, ____, true)
+ ELEM(p, true, true)
+ ELEM(param, ____, ____)
+ ELEM(picture, ____, true)
+ ELEM(plaintext, ____, true)
+ ELEM(pre, true, true)
+ ELEM(progress, ____, true)
+ ELEM(q, ____, true)
+ ELEM(rb, ____, true)
+ ELEM(rp, ____, true)
+ ELEM(rt, ____, true)
+ ELEM(rtc, ____, true)
+ ELEM(ruby, ____, true)
+ ELEM(s, ____, true)
+ ELEM(samp, ____, true)
+ ELEM(script, ____, true)
+ ELEM(section, true, true)
+ ELEM(select, ____, true)
+ ELEM(shadow, ____, true)
+ ELEM(small, ____, true)
+ ELEM(source, ____, ____)
+ ELEM(span, ____, true)
+ ELEM(strike, ____, true)
+ ELEM(strong, ____, true)
+ ELEM(style, ____, true)
+ ELEM(sub, ____, true)
+ ELEM(summary, true, true)
+ ELEM(sup, ____, true)
+ ELEM(table, true, true)
+ ELEM(tbody, ____, true)
+ ELEM(td, ____, true)
+ ELEM(textarea, ____, true)
+ ELEM(tfoot, ____, true)
+ ELEM(th, ____, true)
+ ELEM(thead, ____, true)
+ ELEM(template, ____, true)
+ ELEM(time, ____, true)
+ ELEM(title, ____, true)
+ ELEM(tr, ____, true)
+ ELEM(track, ____, ____)
+ ELEM(tt, ____, true)
+ ELEM(u, ____, true)
+ ELEM(ul, true, true)
+ ELEM(var, ____, true)
+ ELEM(video, ____, true)
+ ELEM(wbr, ____, ____)
+ ELEM(xmp, ____, true)
+ ELEM(text, ____, ____)
+ ELEM(whitespace, ____, ____)
+ ELEM(newline, ____, ____)
+ ELEM(comment, ____, true)
+ ELEM(entity, ____, true)
+ ELEM(doctypeDecl, ____, true)
+ ELEM(markupDecl, ____, true)
+ ELEM(instruction, ____, true)
+ ELEM(userdefined, ____, true)
};
#undef ELEM
+#undef ____
bool
nsHTMLElement::IsContainer(nsHTMLTag aId)
{
- return !gHTMLElements[aId].mLeaf;
+ return gHTMLElements[aId].mIsContainer;
}
bool
nsHTMLElement::IsBlock(nsHTMLTag aId)
{
- return gHTMLElements[aId].IsMemberOf(kBlock) ||
- gHTMLElements[aId].IsMemberOf(kBlockEntity) ||
- gHTMLElements[aId].IsMemberOf(kHeading) ||
- gHTMLElements[aId].IsMemberOf(kPreformatted)||
- gHTMLElements[aId].IsMemberOf(kList);
+ return gHTMLElements[aId].mIsBlock;
}
#ifdef DEBUG
void
CheckElementTable()
{
for (nsHTMLTag t = eHTMLTag_unknown;
t <= eHTMLTag_userdefined;
--- a/toolkit/components/browser/nsIEmbeddingSiteWindow.idl
+++ b/toolkit/components/browser/nsIEmbeddingSiteWindow.idl
@@ -129,17 +129,17 @@ interface nsIEmbeddingSiteWindow : nsISu
/**
* Visibility of the window.
*/
attribute boolean visibility;
/**
* Title of the window.
*/
- attribute wstring title;
+ attribute AString title;
/**
* Native window for the site's window. The implementor should copy the
* native window object into the address supplied by the caller. The
* type of the native window that the address refers to is platform
* and OS specific as follows:
*
* <ul>
--- a/toolkit/components/browser/nsWebBrowser.cpp
+++ b/toolkit/components/browser/nsWebBrowser.cpp
@@ -1577,28 +1577,27 @@ nsWebBrowser::SetFocus()
nsCOMPtr<nsPIDOMWindowOuter> window = GetWindow();
NS_ENSURE_TRUE(window, NS_ERROR_FAILURE);
nsCOMPtr<nsIFocusManager> fm = do_GetService(FOCUSMANAGER_CONTRACTID);
return fm ? fm->SetFocusedWindow(window) : NS_OK;
}
NS_IMETHODIMP
-nsWebBrowser::GetTitle(char16_t** aTitle)
+nsWebBrowser::GetTitle(nsAString& aTitle)
{
- NS_ENSURE_ARG_POINTER(aTitle);
NS_ENSURE_STATE(mDocShell);
NS_ENSURE_SUCCESS(mDocShellAsWin->GetTitle(aTitle), NS_ERROR_FAILURE);
return NS_OK;
}
NS_IMETHODIMP
-nsWebBrowser::SetTitle(const char16_t* aTitle)
+nsWebBrowser::SetTitle(const nsAString& aTitle)
{
NS_ENSURE_STATE(mDocShell);
NS_ENSURE_SUCCESS(mDocShellAsWin->SetTitle(aTitle), NS_ERROR_FAILURE);
return NS_OK;
}
--- a/toolkit/components/url-classifier/nsUrlClassifierPrefixSet.cpp
+++ b/toolkit/components/url-classifier/nsUrlClassifierPrefixSet.cpp
@@ -394,16 +394,18 @@ nsUrlClassifierPrefixSet::StoreToFile(ns
LOG(("Saving PrefixSet successful\n"));
return NS_OK;
}
nsresult
nsUrlClassifierPrefixSet::LoadPrefixes(nsIInputStream* in)
{
+ mCanary.Check();
+
uint32_t magic;
uint32_t read;
nsresult rv = in->Read(reinterpret_cast<char*>(&magic), sizeof(uint32_t), &read);
NS_ENSURE_SUCCESS(rv, rv);
NS_ENSURE_TRUE(read == sizeof(uint32_t), NS_ERROR_FAILURE);
if (magic == PREFIXSET_VERSION_MAGIC) {
@@ -484,16 +486,18 @@ nsUrlClassifierPrefixSet::CalculatePreal
fileSize += 2 * mIndexPrefixes.Length() * sizeof(uint32_t);
fileSize += deltas * sizeof(uint16_t);
return fileSize;
}
nsresult
nsUrlClassifierPrefixSet::WritePrefixes(nsIOutputStream* out)
{
+ mCanary.Check();
+
uint32_t written;
uint32_t writelen = sizeof(uint32_t);
uint32_t magic = PREFIXSET_VERSION_MAGIC;
nsresult rv = out->Write(reinterpret_cast<char*>(&magic), writelen, &written);
NS_ENSURE_SUCCESS(rv, rv);
NS_ENSURE_TRUE(written == writelen, NS_ERROR_FAILURE);
uint32_t indexSize = mIndexPrefixes.Length();
--- a/toolkit/components/url-classifier/nsUrlClassifierPrefixSet.h
+++ b/toolkit/components/url-classifier/nsUrlClassifierPrefixSet.h
@@ -14,16 +14,17 @@
#include "nsIMutableArray.h"
#include "nsIFileStreams.h"
#include "nsIUrlClassifierPrefixSet.h"
#include "nsTArray.h"
#include "nsToolkitCompsCID.h"
#include "mozilla/FileUtils.h"
#include "mozilla/MemoryReporting.h"
#include "mozilla/Mutex.h"
+#include "mozilla/Poison.h"
namespace mozilla {
namespace safebrowsing {
class VariableLengthPrefixSet;
} // namespace safebrowsing
} // namespace mozilla
@@ -79,11 +80,12 @@ private:
// Index to the place that matches the closest lower
// prefix from mIndexPrefix. Then every "delta" corresponds
// to a prefix in the PrefixSet.
nsTArray<nsTArray<uint16_t> > mIndexDeltas;
// how many prefixes we have.
uint32_t mTotalPrefixes;
nsCString mMemoryReportPath;
+ mozilla::CorruptionCanary mCanary;
};
#endif
--- a/toolkit/content/contentAreaUtils.js
+++ b/toolkit/content/contentAreaUtils.js
@@ -1259,15 +1259,19 @@ function openURL(aURL) {
}
}
var channel = NetUtil.newChannel({
uri,
loadUsingSystemPrincipal: true
});
+ if (channel) {
+ channel.channelIsForDownload = true;
+ }
+
var uriLoader = Components.classes["@mozilla.org/uriloader;1"]
.getService(Components.interfaces.nsIURILoader);
uriLoader.openURI(channel,
Components.interfaces.nsIURILoader.IS_CONTENT_PREFERRED,
uriListener);
}
}
--- a/toolkit/content/tests/browser/browser_saveImageURL.js
+++ b/toolkit/content/tests/browser/browser_saveImageURL.js
@@ -32,16 +32,25 @@ add_task(async function preferred_API()
url: IMAGE_PAGE,
}, async function(browser) {
let url = await ContentTask.spawn(browser, null, async function() {
let image = content.document.getElementById("image");
return image.href;
});
saveImageURL(url, "image.jpg", null, true, false, null, null, null, null, false);
+ let channel = content.document.docShell.currentDocumentChannel;
+ if (channel) {
+ ok(true, channel.QueryInterface(Ci.nsIHttpChannelInternal)
+ .channelIsForDownload);
+
+ // Throttleable is the only class flag assigned to downloads.
+ ok(channel.QueryInterface(Ci.nsIClassOfService).classFlags,
+ Ci.nsIClassOfService.Throttleable);
+ }
await waitForFilePicker();
});
});
/**
* Test that saveImageURL will still work when passed a document instead
* of the aIsContentWindowPrivate argument. This is the deprecated API, and
* will not work in apps using remote browsers having PREF_UNSAFE_FORBIDDEN
@@ -59,12 +68,21 @@ add_task(async function deprecated_API()
return image.href;
});
// Now get the document directly from content. If we run this test with
// e10s-enabled, this will be a CPOW, which is forbidden. We'll just
// pass the XUL document instead to test this interface.
let doc = document;
+ let channel = content.document.docShell.currentDocumentChannel;
+ if (channel) {
+ ok(true, channel.QueryInterface(Ci.nsIHttpChannelInternal)
+ .channelIsForDownload);
+
+ // Throttleable is the only class flag assigned to downloads.
+ ok(channel.QueryInterface(Ci.nsIClassOfService).classFlags,
+ Ci.nsIClassOfService.Throttleable);
+ }
saveImageURL(url, "image.jpg", null, true, false, null, doc, null, null);
await waitForFilePicker();
});
});
--- a/toolkit/xre/nsNativeAppSupportWin.cpp
+++ b/toolkit/xre/nsNativeAppSupportWin.cpp
@@ -988,17 +988,17 @@ nsNativeAppSupportWin::HandleDDENotifica
if ( !baseWindow ) {
break;
}
// And from the base window we can get the title.
nsString title;
if(!baseWindow) {
break;
}
- baseWindow->GetTitle(getter_Copies(title));
+ baseWindow->GetTitle(title);
// Escape any double-quotes in the title.
escapeQuotes( title );
// Use a string buffer for the output data, first
// save a quote.
nsAutoCString outpt( NS_LITERAL_CSTRING("\"") );
// Now copy the URL converting the Unicode string
// to a single-byte ASCII string
--- a/widget/cocoa/nsCocoaWindow.mm
+++ b/widget/cocoa/nsCocoaWindow.mm
@@ -482,25 +482,16 @@ nsresult nsCocoaWindow::CreateNativeWind
// BorderlessWindow class.
else if (features == NSBorderlessWindowMask)
windowClass = [BorderlessWindow class];
// Create the window
mWindow = [[windowClass alloc] initWithContentRect:contentRect styleMask:features
backing:NSBackingStoreBuffered defer:YES];
- if ([mWindow respondsToSelector:@selector(setTitleVisibility:)]) {
- // By default, hide window titles.
- [mWindow setTitleVisibility:NSWindowTitleHidden];
- }
- if ([mWindow respondsToSelector:@selector(setTitlebarAppearsTransparent:)]) {
- // By default, hide window titlebars.
- [mWindow setTitlebarAppearsTransparent:YES];
- }
-
// setup our notification delegate. Note that setDelegate: does NOT retain.
mDelegate = [[WindowDelegate alloc] initWithGeckoWindow:this];
[mWindow setDelegate:mDelegate];
// Make sure that the content rect we gave has been honored.
NSRect wantedFrame = [mWindow frameRectForContentRect:contentRect];
if (!NSEqualRects([mWindow frame], wantedFrame)) {
// This can happen when the window is not on the primary screen.
--- a/widget/nsIBaseWindow.idl
+++ b/widget/nsIBaseWindow.idl
@@ -221,10 +221,10 @@ interface nsIBaseWindow : nsISupports
/**
* Give the window focus.
*/
void setFocus();
/*
Title of the window.
*/
- attribute wstring title;
+ attribute AString title;
};
--- a/xpfe/appshell/nsAppShellService.cpp
+++ b/xpfe/appshell/nsAppShellService.cpp
@@ -375,22 +375,22 @@ WebBrowserChrome2Stub::GetVisibility(boo
}
NS_IMETHODIMP
WebBrowserChrome2Stub::SetVisibility(bool aVisibility)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
-WebBrowserChrome2Stub::GetTitle(char16_t** aTitle)
+WebBrowserChrome2Stub::GetTitle(nsAString& aTitle)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
-WebBrowserChrome2Stub::SetTitle(const char16_t* aTitle)
+WebBrowserChrome2Stub::SetTitle(const nsAString& aTitle)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
WebBrowserChrome2Stub::GetSiteWindow(void** aSiteWindow)
{
return NS_ERROR_NOT_IMPLEMENTED;
--- a/xpfe/appshell/nsChromeTreeOwner.cpp
+++ b/xpfe/appshell/nsChromeTreeOwner.cpp
@@ -425,23 +425,23 @@ NS_IMETHODIMP nsChromeTreeOwner::GetMain
}
NS_IMETHODIMP nsChromeTreeOwner::SetFocus()
{
NS_ENSURE_STATE(mXULWindow);
return mXULWindow->SetFocus();
}
-NS_IMETHODIMP nsChromeTreeOwner::GetTitle(char16_t** aTitle)
+NS_IMETHODIMP nsChromeTreeOwner::GetTitle(nsAString& aTitle)
{
NS_ENSURE_STATE(mXULWindow);
return mXULWindow->GetTitle(aTitle);
}
-NS_IMETHODIMP nsChromeTreeOwner::SetTitle(const char16_t* aTitle)
+NS_IMETHODIMP nsChromeTreeOwner::SetTitle(const nsAString& aTitle)
{
NS_ENSURE_STATE(mXULWindow);
return mXULWindow->SetTitle(aTitle);
}
//*****************************************************************************
// nsChromeTreeOwner::nsIWebProgressListener
//*****************************************************************************
--- a/xpfe/appshell/nsContentTreeOwner.cpp
+++ b/xpfe/appshell/nsContentTreeOwner.cpp
@@ -708,25 +708,24 @@ NS_IMETHODIMP nsContentTreeOwner::GetMai
}
NS_IMETHODIMP nsContentTreeOwner::SetFocus()
{
NS_ENSURE_STATE(mXULWindow);
return mXULWindow->SetFocus();
}
-NS_IMETHODIMP nsContentTreeOwner::GetTitle(char16_t** aTitle)
+NS_IMETHODIMP nsContentTreeOwner::GetTitle(nsAString& aTitle)
{
- NS_ENSURE_ARG_POINTER(aTitle);
NS_ENSURE_STATE(mXULWindow);
return mXULWindow->GetTitle(aTitle);
}
-NS_IMETHODIMP nsContentTreeOwner::SetTitle(const char16_t* aTitle)
+NS_IMETHODIMP nsContentTreeOwner::SetTitle(const nsAString& aTitle)
{
// We only allow the title to be set from the primary content shell
if(!mPrimary || !mContentTitleSetting)
return NS_OK;
NS_ENSURE_STATE(mXULWindow);
nsAutoString title;
@@ -805,17 +804,17 @@ NS_IMETHODIMP nsContentTreeOwner::SetTit
}
}
nsIDocument* document = docShellElement->OwnerDoc();
ErrorResult rv;
document->SetTitle(title, rv);
return rv.StealNSResult();
}
- return mXULWindow->SetTitle(title.get());
+ return mXULWindow->SetTitle(title);
}
//*****************************************************************************
// nsContentTreeOwner: nsIWindowProvider
//*****************************************************************************
NS_IMETHODIMP
nsContentTreeOwner::ProvideWindow(mozIDOMWindowProxy* aParent,
uint32_t aChromeFlags,
@@ -1143,23 +1142,23 @@ nsSiteWindow::GetVisibility(bool *aVisib
NS_IMETHODIMP
nsSiteWindow::SetVisibility(bool aVisibility)
{
return mAggregator->SetVisibility(aVisibility);
}
NS_IMETHODIMP
-nsSiteWindow::GetTitle(char16_t * *aTitle)
+nsSiteWindow::GetTitle(nsAString& aTitle)
{
return mAggregator->GetTitle(aTitle);
}
NS_IMETHODIMP
-nsSiteWindow::SetTitle(const char16_t * aTitle)
+nsSiteWindow::SetTitle(const nsAString& aTitle)
{
return mAggregator->SetTitle(aTitle);
}
NS_IMETHODIMP
nsSiteWindow::GetSiteWindow(void **aSiteWindow)
{
return mAggregator->GetParentNativeWindow(aSiteWindow);
--- a/xpfe/appshell/nsIWindowMediator.idl
+++ b/xpfe/appshell/nsIWindowMediator.idl
@@ -104,17 +104,17 @@ interface nsIWindowMediator: nsISupports
[noscript] void updateWindowTimeStamp(in nsIXULWindow aWindow);
/** Call this method when a window's title changes. Listeners (see
* addListener) will be notified through their onWindowTitleChange method.
* @param aWindow the window whose title has changed
* @param inTitle the window's new title
*/
[noscript] void updateWindowTitle(in nsIXULWindow aWindow,
- in wstring inTitle );
+ in AString inTitle);
/* z-ordering: */
const unsigned long zLevelTop = 1;
const unsigned long zLevelBottom = 2;
const unsigned long zLevelBelow = 3; // below some window
/** A window wants to be moved in z-order. Calculate whether and how
--- a/xpfe/appshell/nsIWindowMediatorListener.idl
+++ b/xpfe/appshell/nsIWindowMediatorListener.idl
@@ -5,15 +5,14 @@
#include "nsISupports.idl"
interface nsIXULWindow;
[scriptable, uuid(2F276982-0D60-4377-A595-D350BA516395)]
interface nsIWindowMediatorListener : nsISupports
{
- void onWindowTitleChange(in nsIXULWindow window,
- in wstring newTitle);
+ void onWindowTitleChange(in nsIXULWindow window, in AString newTitle);
void onOpenWindow(in nsIXULWindow window);
void onCloseWindow(in nsIXULWindow window);
};
--- a/xpfe/appshell/nsWindowMediator.cpp
+++ b/xpfe/appshell/nsWindowMediator.cpp
@@ -391,17 +391,17 @@ nsWindowMediator::UpdateWindowTimeStamp(
info->mTimeStamp = ++mTimeStamp;
return NS_OK;
}
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP
nsWindowMediator::UpdateWindowTitle(nsIXULWindow* inWindow,
- const char16_t* inTitle)
+ const nsAString& inTitle)
{
MOZ_RELEASE_ASSERT(NS_IsMainThread());
NS_ENSURE_STATE(mReady);
if (GetInfoFor(inWindow)) {
ListenerArray::ForwardIterator iter(mListeners);
while (iter.HasMore()) {
iter.GetNext()->OnWindowTitleChange(inWindow, inTitle);
}
--- a/xpfe/appshell/nsXULWindow.cpp
+++ b/xpfe/appshell/nsXULWindow.cpp
@@ -885,27 +885,23 @@ NS_IMETHODIMP nsXULWindow::GetMainWidget
NS_IMETHODIMP nsXULWindow::SetFocus()
{
//XXX First Check In
NS_ASSERTION(false, "Not Yet Implemented");
return NS_OK;
}
-NS_IMETHODIMP nsXULWindow::GetTitle(char16_t** aTitle)
+NS_IMETHODIMP nsXULWindow::GetTitle(nsAString& aTitle)
{
- NS_ENSURE_ARG_POINTER(aTitle);
-
- *aTitle = ToNewUnicode(mTitle);
- if (!*aTitle)
- return NS_ERROR_OUT_OF_MEMORY;
+ aTitle = mTitle;
return NS_OK;
}
-NS_IMETHODIMP nsXULWindow::SetTitle(const char16_t* aTitle)
+NS_IMETHODIMP nsXULWindow::SetTitle(const nsAString& aTitle)
{
NS_ENSURE_STATE(mWindow);
mTitle.Assign(aTitle);
mTitle.StripCRLF();
NS_ENSURE_SUCCESS(mWindow->SetTitle(mTitle), NS_ERROR_FAILURE);
// Tell the window mediator that a title has changed
nsCOMPtr<nsIWindowMediator> windowMediator(do_GetService(NS_WINDOWMEDIATOR_CONTRACTID));
--- a/xpfe/components/windowds/nsWindowDataSource.cpp
+++ b/xpfe/components/windowds/nsWindowDataSource.cpp
@@ -116,33 +116,34 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(
NS_INTERFACE_MAP_END
// nsIWindowMediatorListener implementation
// handle notifications from the window mediator and reflect them into
// RDF
NS_IMETHODIMP
nsWindowDataSource::OnWindowTitleChange(nsIXULWindow *window,
- const char16_t *newTitle)
+ const nsAString& newTitle)
{
nsresult rv;
nsCOMPtr<nsIRDFResource> windowResource;
mWindowResources.Get(window, getter_AddRefs(windowResource));
// oops, make sure this window is in the hashtable!
if (!windowResource) {
OnOpenWindow(window);
mWindowResources.Get(window, getter_AddRefs(windowResource));
}
NS_ENSURE_TRUE(windowResource, NS_ERROR_UNEXPECTED);
nsCOMPtr<nsIRDFLiteral> newTitleLiteral;
- rv = gRDFService->GetLiteral(newTitle, getter_AddRefs(newTitleLiteral));
+ rv = gRDFService->GetLiteral(PromiseFlatString(newTitle).get(),
+ getter_AddRefs(newTitleLiteral));
NS_ENSURE_SUCCESS(rv, rv);
// get the old title
nsCOMPtr<nsIRDFNode> oldTitleNode;
rv = GetTarget(windowResource, kNC_Name, true,
getter_AddRefs(oldTitleNode));
// assert the change