Improved annotations' display/behavior.

Added an "InteractiveAnnotation" class to homogenize the annotations' structure (highlighting) and user interactions (for now, used for text and link annotations).

Text annotations:
The appearance (AP) has priority over the icon (Name).
The popup extends horizontally (up to a limit) as well as vertically.
Reduced the title's font size.
The annotation's color (C) is used to color the popup's background.
On top of the mouseover show/hide behavior, a click on the icon will lock the annotation open (for mobile purposes). It can be closed with another click on either the icon or the popup.

An annotation printing is conditioned by its "print" bit
Unsupported annotations are not displayed at all.
This commit is contained in:
Samuel Chantaraud 2014-03-07 10:48:42 -04:00
parent 3e931048f2
commit 076b3433b4
8 changed files with 305 additions and 131 deletions

View File

@ -134,7 +134,7 @@ var Page = (function PageClosure() {
}.bind(this)); }.bind(this));
return promise; return promise;
}, },
getOperatorList: function Page_getOperatorList(handler) { getOperatorList: function Page_getOperatorList(handler, intent) {
var self = this; var self = this;
var promise = new LegacyPromise(); var promise = new LegacyPromise();
@ -169,11 +169,12 @@ var Page = (function PageClosure() {
var contentStream = data[0]; var contentStream = data[0];
var opList = new OperatorList(handler, self.pageIndex); var opList = new OperatorList(intent, handler, self.pageIndex);
handler.send('StartRenderPage', { handler.send('StartRenderPage', {
transparency: partialEvaluator.hasBlendModes(self.resources), transparency: partialEvaluator.hasBlendModes(self.resources),
pageIndex: self.pageIndex pageIndex: self.pageIndex,
intent: intent
}); });
partialEvaluator.getOperatorList(contentStream, self.resources, opList); partialEvaluator.getOperatorList(contentStream, self.resources, opList);
pageListPromise.resolve(opList); pageListPromise.resolve(opList);
@ -191,7 +192,7 @@ var Page = (function PageClosure() {
} }
var annotationsReadyPromise = Annotation.appendToOperatorList( var annotationsReadyPromise = Annotation.appendToOperatorList(
annotations, pageOpList, pdfManager, partialEvaluator); annotations, pageOpList, pdfManager, partialEvaluator, intent);
annotationsReadyPromise.then(function () { annotationsReadyPromise.then(function () {
pageOpList.flush(true); pageOpList.flush(true);
promise.resolve(pageOpList); promise.resolve(pageOpList);

View File

@ -1376,7 +1376,7 @@ var OperatorList = (function OperatorListClosure() {
} }
function OperatorList(messageHandler, pageIndex) { function OperatorList(intent, messageHandler, pageIndex) {
this.messageHandler = messageHandler; this.messageHandler = messageHandler;
// When there isn't a message handler the fn array needs to be able to grow // When there isn't a message handler the fn array needs to be able to grow
// since we can't flush the operators. // since we can't flush the operators.
@ -1389,6 +1389,7 @@ var OperatorList = (function OperatorListClosure() {
this.dependencies = {}; this.dependencies = {};
this.pageIndex = pageIndex; this.pageIndex = pageIndex;
this.fnIndex = 0; this.fnIndex = 0;
this.intent = intent;
} }
OperatorList.prototype = { OperatorList.prototype = {
@ -1449,7 +1450,8 @@ var OperatorList = (function OperatorListClosure() {
lastChunk: lastChunk, lastChunk: lastChunk,
length: this.length length: this.length
}, },
pageIndex: this.pageIndex pageIndex: this.pageIndex,
intent: this.intent
}, null, transfers); }, null, transfers);
this.dependencies = []; this.dependencies = [];
this.fnIndex = 0; this.fnIndex = 0;

View File

@ -334,7 +334,7 @@ var WorkerMessageHandler = PDFJS.WorkerMessageHandler = {
var pageNum = data.pageIndex + 1; var pageNum = data.pageIndex + 1;
var start = Date.now(); var start = Date.now();
// Pre compile the pdf page and fetch the fonts/images. // Pre compile the pdf page and fetch the fonts/images.
page.getOperatorList(handler).then(function(operatorList) { page.getOperatorList(handler, data.intent).then(function(operatorList) {
info('page=' + pageNum + ' - getOperatorList: time=' + info('page=' + pageNum + ' - getOperatorList: time=' +
(Date.now() - start) + 'ms, len=' + operatorList.fnArray.length); (Date.now() - start) + 'ms, len=' + operatorList.fnArray.length);
@ -366,7 +366,8 @@ var WorkerMessageHandler = PDFJS.WorkerMessageHandler = {
handler.send('PageError', { handler.send('PageError', {
pageNum: pageNum, pageNum: pageNum,
error: wrappedException error: wrappedException,
intent: data.intent
}); });
}); });
}); });

View File

@ -341,10 +341,9 @@ var PDFPageProxy = (function PDFPageProxyClosure() {
this.stats.enabled = !!globalScope.PDFJS.enableStats; this.stats.enabled = !!globalScope.PDFJS.enableStats;
this.commonObjs = transport.commonObjs; this.commonObjs = transport.commonObjs;
this.objs = new PDFObjects(); this.objs = new PDFObjects();
this.receivingOperatorList = false;
this.cleanupAfterRender = false; this.cleanupAfterRender = false;
this.pendingDestroy = false; this.pendingDestroy = false;
this.renderTasks = []; this.intentStates = {};
} }
PDFPageProxy.prototype = /** @lends PDFPageProxy.prototype */ { PDFPageProxy.prototype = /** @lends PDFPageProxy.prototype */ {
/** /**
@ -423,12 +422,21 @@ var PDFPageProxy = (function PDFPageProxyClosure() {
// this call to render. // this call to render.
this.pendingDestroy = false; this.pendingDestroy = false;
var renderingIntent = 'intent' in params ?
(params.intent == 'print' ? 'print' : 'display') :
'display';
if (!this.intentStates[renderingIntent]) {
this.intentStates[renderingIntent] = {};
}
var intentState = this.intentStates[renderingIntent];
// If there is no displayReadyPromise yet, then the operatorList was never // If there is no displayReadyPromise yet, then the operatorList was never
// requested before. Make the request and create the promise. // requested before. Make the request and create the promise.
if (!this.displayReadyPromise) { if (!intentState.displayReadyPromise) {
this.receivingOperatorList = true; intentState.receivingOperatorList = true;
this.displayReadyPromise = new LegacyPromise(); intentState.displayReadyPromise = new LegacyPromise();
this.operatorList = { intentState.operatorList = {
fnArray: [], fnArray: [],
argsArray: [], argsArray: [],
lastChunk: false lastChunk: false
@ -436,18 +444,23 @@ var PDFPageProxy = (function PDFPageProxyClosure() {
this.stats.time('Page Request'); this.stats.time('Page Request');
this.transport.messageHandler.send('RenderPageRequest', { this.transport.messageHandler.send('RenderPageRequest', {
pageIndex: this.pageNumber - 1 pageIndex: this.pageNumber - 1,
intent: renderingIntent
}); });
} }
var internalRenderTask = new InternalRenderTask(complete, params, var internalRenderTask = new InternalRenderTask(complete, params,
this.objs, this.commonObjs, this.objs, this.commonObjs,
this.operatorList, this.pageNumber); intentState.operatorList,
this.renderTasks.push(internalRenderTask); this.pageNumber);
if (!intentState.renderTasks) {
intentState.renderTasks = [];
}
intentState.renderTasks.push(internalRenderTask);
var renderTask = new RenderTask(internalRenderTask); var renderTask = new RenderTask(internalRenderTask);
var self = this; var self = this;
this.displayReadyPromise.then( intentState.displayReadyPromise.then(
function pageDisplayReadyPromise(transparency) { function pageDisplayReadyPromise(transparency) {
if (self.pendingDestroy) { if (self.pendingDestroy) {
complete(); complete();
@ -463,9 +476,9 @@ var PDFPageProxy = (function PDFPageProxyClosure() {
); );
function complete(error) { function complete(error) {
var i = self.renderTasks.indexOf(internalRenderTask); var i = intentState.renderTasks.indexOf(internalRenderTask);
if (i >= 0) { if (i >= 0) {
self.renderTasks.splice(i, 1); intentState.renderTasks.splice(i, 1);
} }
if (self.cleanupAfterRender) { if (self.cleanupAfterRender) {
@ -513,14 +526,17 @@ var PDFPageProxy = (function PDFPageProxyClosure() {
*/ */
_tryDestroy: function PDFPageProxy__destroy() { _tryDestroy: function PDFPageProxy__destroy() {
if (!this.pendingDestroy || if (!this.pendingDestroy ||
this.renderTasks.length !== 0 || Object.keys(this.intentStates).some(function(intent) {
this.receivingOperatorList) { var intentState = this.intentStates[intent];
return intentState.renderTasks.length !== 0 ||
intentState.receivingOperatorList;
}, this)) {
return; return;
} }
delete this.operatorList; Object.keys(this.intentStates).forEach(function(intent) {
delete this.displayReadyPromise; delete this.intentStates[intent];
delete this.annotationsPromise; }, this);
this.objs.clear(); this.objs.clear();
this.pendingDestroy = false; this.pendingDestroy = false;
}, },
@ -528,28 +544,33 @@ var PDFPageProxy = (function PDFPageProxyClosure() {
* For internal use only. * For internal use only.
* @ignore * @ignore
*/ */
_startRenderPage: function PDFPageProxy_startRenderPage(transparency) { _startRenderPage: function PDFPageProxy_startRenderPage(transparency,
this.displayReadyPromise.resolve(transparency); intent) {
var intentState = this.intentStates[intent];
intentState.displayReadyPromise.resolve(transparency);
}, },
/** /**
* For internal use only. * For internal use only.
* @ignore * @ignore
*/ */
_renderPageChunk: function PDFPageProxy_renderPageChunk(operatorListChunk) { _renderPageChunk: function PDFPageProxy_renderPageChunk(operatorListChunk,
intent) {
var intentState = this.intentStates[intent];
// Add the new chunk to the current operator list. // Add the new chunk to the current operator list.
for (var i = 0, ii = operatorListChunk.length; i < ii; i++) { for (var i = 0, ii = operatorListChunk.length; i < ii; i++) {
this.operatorList.fnArray.push(operatorListChunk.fnArray[i]); intentState.operatorList.fnArray.push(operatorListChunk.fnArray[i]);
this.operatorList.argsArray.push(operatorListChunk.argsArray[i]); intentState.operatorList.argsArray.push(
operatorListChunk.argsArray[i]);
} }
this.operatorList.lastChunk = operatorListChunk.lastChunk; intentState.operatorList.lastChunk = operatorListChunk.lastChunk;
// Notify all the rendering tasks there are more operators to be consumed. // Notify all the rendering tasks there are more operators to be consumed.
for (var i = 0; i < this.renderTasks.length; i++) { for (var i = 0; i < intentState.renderTasks.length; i++) {
this.renderTasks[i].operatorListChanged(); intentState.renderTasks[i].operatorListChanged();
} }
if (operatorListChunk.lastChunk) { if (operatorListChunk.lastChunk) {
this.receivingOperatorList = false; intentState.receivingOperatorList = false;
this._tryDestroy(); this._tryDestroy();
} }
} }
@ -775,13 +796,13 @@ var WorkerTransport = (function WorkerTransportClosure() {
var page = this.pageCache[data.pageIndex]; var page = this.pageCache[data.pageIndex];
page.stats.timeEnd('Page Request'); page.stats.timeEnd('Page Request');
page._startRenderPage(data.transparency); page._startRenderPage(data.transparency, data.intent);
}, this); }, this);
messageHandler.on('RenderPageChunk', function transportRender(data) { messageHandler.on('RenderPageChunk', function transportRender(data) {
var page = this.pageCache[data.pageIndex]; var page = this.pageCache[data.pageIndex];
page._renderPageChunk(data.operatorList); page._renderPageChunk(data.operatorList, data.intent);
}, this); }, this);
messageHandler.on('commonobj', function transportObj(data) { messageHandler.on('commonobj', function transportObj(data) {
@ -824,8 +845,9 @@ var WorkerTransport = (function WorkerTransportClosure() {
var pageIndex = data[1]; var pageIndex = data[1];
var type = data[2]; var type = data[2];
var pageProxy = this.pageCache[pageIndex]; var pageProxy = this.pageCache[pageIndex];
if (pageProxy.objs.hasData(id)) if (pageProxy.objs.hasData(id)) {
return; return;
}
switch (type) { switch (type) {
case 'JpegStream': case 'JpegStream':
@ -861,10 +883,11 @@ var WorkerTransport = (function WorkerTransportClosure() {
this.workerReadyPromise.reject(data); this.workerReadyPromise.reject(data);
}, this); }, this);
messageHandler.on('PageError', function transportError(data) { messageHandler.on('PageError', function transportError(data, intent) {
var page = this.pageCache[data.pageNum - 1]; var page = this.pageCache[data.pageNum - 1];
if (page.displayReadyPromise) var intentState = page.intentStates[intent];
page.displayReadyPromise.reject(data.error); if (intentState.displayReadyPromise)
intentState.displayReadyPromise.reject(data.error);
else else
error(data.error); error(data.error);
}, this); }, this);

View File

@ -21,6 +21,9 @@
'use strict'; 'use strict';
var HIGHLIGHT_OFFSET = 4; // px
var SUPPORTED_TYPES = ['Link', 'Text', 'Widget'];
var Annotation = (function AnnotationClosure() { var Annotation = (function AnnotationClosure() {
// 12.5.5: Algorithm: Appearance streams // 12.5.5: Algorithm: Appearance streams
function getTransformMatrix(rect, bbox, matrix) { function getTransformMatrix(rect, bbox, matrix) {
@ -143,25 +146,50 @@ var Annotation = (function AnnotationClosure() {
}, },
// TODO(mack): Remove this, it's not really that helpful. // TODO(mack): Remove this, it's not really that helpful.
getEmptyContainer: function Annotation_getEmptyContainer(tagName, rect) { getEmptyContainer: function Annotation_getEmptyContainer(tagName, rect,
borderWidth) {
assert(!isWorker, assert(!isWorker,
'getEmptyContainer() should be called from main thread'); 'getEmptyContainer() should be called from main thread');
var bWidth = borderWidth || 0;
rect = rect || this.data.rect; rect = rect || this.data.rect;
var element = document.createElement(tagName); var element = document.createElement(tagName);
element.style.width = Math.ceil(rect[2] - rect[0]) + 'px'; element.style.borderWidth = bWidth + 'px';
element.style.height = Math.ceil(rect[3] - rect[1]) + 'px'; var width = rect[2] - rect[0] - 2 * bWidth;
var height = rect[3] - rect[1] - 2 * bWidth;
element.style.width = width + 'px';
element.style.height = height + 'px';
return element; return element;
}, },
isInvisible: function Annotation_isInvisible() {
var data = this.data;
if (data && SUPPORTED_TYPES.indexOf(data.subtype) !== -1) {
return false;
} else {
return !!(data &&
data.annotationFlags && // Default: not invisible
data.annotationFlags & 0x1); // Invisible
}
},
isViewable: function Annotation_isViewable() { isViewable: function Annotation_isViewable() {
var data = this.data; var data = this.data;
return !!( return !!(!this.isInvisible() &&
data && data &&
(!data.annotationFlags || (!data.annotationFlags ||
!(data.annotationFlags & 0x22)) && // Hidden or NoView !(data.annotationFlags & 0x22)) && // Hidden or NoView
data.rect // rectangle is nessessary data.rect); // rectangle is nessessary
); },
isPrintable: function Annotation_isPrintable() {
var data = this.data;
return !!(!this.isInvisible() &&
data &&
data.annotationFlags && // Default: not printable
data.annotationFlags & 0x4 && // Print
data.rect); // rectangle is nessessary
}, },
loadResources: function(keys) { loadResources: function(keys) {
@ -182,7 +210,7 @@ var Annotation = (function AnnotationClosure() {
return promise; return promise;
}, },
getOperatorList: function Annotation_getToOperatorList(evaluator) { getOperatorList: function Annotation_getOperatorList(evaluator) {
var promise = new LegacyPromise(); var promise = new LegacyPromise();
@ -289,7 +317,7 @@ var Annotation = (function AnnotationClosure() {
var annotation = new Constructor(params); var annotation = new Constructor(params);
if (annotation.isViewable()) { if (annotation.isViewable() || annotation.isPrintable()) {
return annotation; return annotation;
} else { } else {
warn('unimplemented annotation type: ' + subtype); warn('unimplemented annotation type: ' + subtype);
@ -297,7 +325,7 @@ var Annotation = (function AnnotationClosure() {
}; };
Annotation.appendToOperatorList = function Annotation_appendToOperatorList( Annotation.appendToOperatorList = function Annotation_appendToOperatorList(
annotations, opList, pdfManager, partialEvaluator) { annotations, opList, pdfManager, partialEvaluator, intent) {
function reject(e) { function reject(e) {
annotationsReadyPromise.reject(e); annotationsReadyPromise.reject(e);
@ -307,7 +335,11 @@ var Annotation = (function AnnotationClosure() {
var annotationPromises = []; var annotationPromises = [];
for (var i = 0, n = annotations.length; i < n; ++i) { for (var i = 0, n = annotations.length; i < n; ++i) {
annotationPromises.push(annotations[i].getOperatorList(partialEvaluator)); if (intent === 'display' && annotations[i].isViewable() ||
intent === 'print' && annotations[i].isPrintable()) {
annotationPromises.push(
annotations[i].getOperatorList(partialEvaluator));
}
} }
Promise.all(annotationPromises).then(function(datas) { Promise.all(annotationPromises).then(function(datas) {
opList.addOp(OPS.beginAnnotations, []); opList.addOp(OPS.beginAnnotations, []);
@ -519,9 +551,64 @@ var TextWidgetAnnotation = (function TextWidgetAnnotationClosure() {
return TextWidgetAnnotation; return TextWidgetAnnotation;
})(); })();
var InteractiveAnnotation = (function InteractiveAnnotationClosure() {
function InteractiveAnnotation(params) {
Annotation.call(this, params);
}
Util.inherit(InteractiveAnnotation, Annotation, {
hasHtml: function InteractiveAnnotation_hasHtml() {
return true;
},
highlight: function InteractiveAnnotation_highlight() {
if (this.highlightElement &&
this.highlightElement.hasAttribute('hidden')) {
this.highlightElement.removeAttribute('hidden');
}
},
unhighlight: function InteractiveAnnotation_unhighlight() {
if (this.highlightElement &&
!this.highlightElement.hasAttribute('hidden')) {
this.highlightElement.setAttribute('hidden', true);
}
},
initContainer: function InteractiveAnnotation_initContainer() {
var item = this.data;
var rect = item.rect;
var container = this.getEmptyContainer('section', rect, item.borderWidth);
container.style.backgroundColor = item.color;
var color = item.color;
var rgb = [];
for (var i = 0; i < 3; ++i) {
rgb[i] = Math.round(color[i] * 255);
}
item.colorCssRgb = Util.makeCssRgb(rgb);
var highlight = document.createElement('div');
highlight.className = 'annotationHighlight';
highlight.style.left = highlight.style.top = -HIGHLIGHT_OFFSET + 'px';
highlight.style.right = highlight.style.bottom = -HIGHLIGHT_OFFSET + 'px';
highlight.setAttribute('hidden', true);
this.highlightElement = highlight;
container.appendChild(this.highlightElement);
return container;
}
});
return InteractiveAnnotation;
})();
var TextAnnotation = (function TextAnnotationClosure() { var TextAnnotation = (function TextAnnotationClosure() {
function TextAnnotation(params) { function TextAnnotation(params) {
Annotation.call(this, params); InteractiveAnnotation.call(this, params);
if (params.data) { if (params.data) {
return; return;
@ -534,22 +621,21 @@ var TextAnnotation = (function TextAnnotationClosure() {
var title = dict.get('T'); var title = dict.get('T');
data.content = stringToPDFString(content || ''); data.content = stringToPDFString(content || '');
data.title = stringToPDFString(title || ''); data.title = stringToPDFString(title || '');
data.name = !dict.has('Name') ? 'Note' : dict.get('Name').name;
if (data.hasAppearance) {
data.name = 'NoIcon';
} else {
data.name = dict.has('Name') ? dict.get('Name').name : 'Note';
}
if (dict.has('C')) {
data.hasBgColor = true;
}
} }
var ANNOT_MIN_SIZE = 10; var ANNOT_MIN_SIZE = 10;
Util.inherit(TextAnnotation, Annotation, { Util.inherit(TextAnnotation, InteractiveAnnotation, {
getOperatorList: function TextAnnotation_getOperatorList(evaluator) {
var promise = new LegacyPromise();
promise.resolve(new OperatorList());
return promise;
},
hasHtml: function TextAnnotation_hasHtml() {
return true;
},
getHtmlElement: function TextAnnotation_getHtmlElement(commonObjs) { getHtmlElement: function TextAnnotation_getHtmlElement(commonObjs) {
assert(!isWorker, 'getHtmlElement() shall be called from main thread'); assert(!isWorker, 'getHtmlElement() shall be called from main thread');
@ -565,23 +651,40 @@ var TextAnnotation = (function TextAnnotationClosure() {
rect[2] = rect[0] + (rect[3] - rect[1]); // make it square rect[2] = rect[0] + (rect[3] - rect[1]); // make it square
} }
var container = this.getEmptyContainer('section', rect); var container = this.initContainer();
container.className = 'annotText'; container.className = 'annotText';
var image = document.createElement('img'); var image = document.createElement('img');
image.style.height = container.style.height; image.style.height = container.style.height;
image.style.width = container.style.width;
var iconName = item.name; var iconName = item.name;
image.src = PDFJS.imageResourcesPath + 'annotation-' + image.src = PDFJS.imageResourcesPath + 'annotation-' +
iconName.toLowerCase() + '.svg'; iconName.toLowerCase() + '.svg';
image.alt = '[{{type}} Annotation]'; image.alt = '[{{type}} Annotation]';
image.dataset.l10nId = 'text_annotation_type'; image.dataset.l10nId = 'text_annotation_type';
image.dataset.l10nArgs = JSON.stringify({type: iconName}); image.dataset.l10nArgs = JSON.stringify({type: iconName});
var contentWrapper = document.createElement('div');
contentWrapper.className = 'annotTextContentWrapper';
contentWrapper.style.left = Math.floor(rect[2] - rect[0] + 5) + 'px';
contentWrapper.style.top = '-10px';
var content = document.createElement('div'); var content = document.createElement('div');
content.className = 'annotTextContent';
content.setAttribute('hidden', true); content.setAttribute('hidden', true);
if (item.hasBgColor) {
var color = item.color;
var rgb = [];
for (var i = 0; i < 3; ++i) {
// Enlighten the color (70%)
var c = Math.round(color[i] * 255);
rgb[i] = Math.round((255 - c) * 0.7) + c;
}
content.style.backgroundColor = Util.makeCssRgb(rgb);
}
var title = document.createElement('h1'); var title = document.createElement('h1');
var text = document.createElement('p'); var text = document.createElement('p');
content.style.left = Math.floor(rect[2] - rect[0]) + 'px';
content.style.top = '0px';
title.textContent = item.title; title.textContent = item.title;
if (!item.content && !item.title) { if (!item.content && !item.title) {
@ -597,28 +700,57 @@ var TextAnnotation = (function TextAnnotationClosure() {
} }
text.appendChild(e); text.appendChild(e);
var showAnnotation = function showAnnotation() { var pinned = false;
var showAnnotation = function showAnnotation(pin) {
if (pin) {
pinned = true;
}
if (content.hasAttribute('hidden')) {
container.style.zIndex += 1; container.style.zIndex += 1;
content.removeAttribute('hidden'); content.removeAttribute('hidden');
}
}; };
var hideAnnotation = function hideAnnotation(e) { var hideAnnotation = function hideAnnotation(unpin) {
if (e.toElement || e.relatedTarget) { // No context menu is used if (unpin) {
pinned = false;
}
if (!content.hasAttribute('hidden') && !pinned) {
container.style.zIndex -= 1; container.style.zIndex -= 1;
content.setAttribute('hidden', true); content.setAttribute('hidden', true);
} }
}; };
content.addEventListener('mouseover', showAnnotation, false); var toggleAnnotation = function toggleAnnotation() {
content.addEventListener('mouseout', hideAnnotation, false); if (pinned) {
image.addEventListener('mouseover', showAnnotation, false); hideAnnotation(true);
image.addEventListener('mouseout', hideAnnotation, false); } else {
showAnnotation(true);
}
};
var self = this;
image.addEventListener('click', function image_clickHandler() {
toggleAnnotation();
}, false);
image.addEventListener('mouseover', function image_mouseOverHandler() {
showAnnotation();
}, false);
image.addEventListener('mouseout', function image_mouseOutHandler() {
hideAnnotation();
}, false);
content.addEventListener('click', function content_clickHandler() {
hideAnnotation(true);
}, false);
} }
content.appendChild(title); content.appendChild(title);
content.appendChild(text); content.appendChild(text);
contentWrapper.appendChild(content);
container.appendChild(image); container.appendChild(image);
container.appendChild(content); container.appendChild(contentWrapper);
return container; return container;
} }
@ -629,7 +761,7 @@ var TextAnnotation = (function TextAnnotationClosure() {
var LinkAnnotation = (function LinkAnnotationClosure() { var LinkAnnotation = (function LinkAnnotationClosure() {
function LinkAnnotation(params) { function LinkAnnotation(params) {
Annotation.call(this, params); InteractiveAnnotation.call(this, params);
if (params.data) { if (params.data) {
return; return;
@ -692,36 +824,28 @@ var LinkAnnotation = (function LinkAnnotationClosure() {
return url; return url;
} }
Util.inherit(LinkAnnotation, Annotation, { Util.inherit(LinkAnnotation, InteractiveAnnotation, {
hasOperatorList: function LinkAnnotation_hasOperatorList() { hasOperatorList: function LinkAnnotation_hasOperatorList() {
return false; return false;
}, },
hasHtml: function LinkAnnotation_hasHtml() {
return true;
},
getHtmlElement: function LinkAnnotation_getHtmlElement(commonObjs) { getHtmlElement: function LinkAnnotation_getHtmlElement(commonObjs) {
var rect = this.data.rect;
var element = document.createElement('a');
var borderWidth = this.data.borderWidth;
element.style.borderWidth = borderWidth + 'px'; var container = this.initContainer();
var color = this.data.color; container.className = 'annotLink';
var rgb = [];
for (var i = 0; i < 3; ++i) {
rgb[i] = Math.round(color[i] * 255);
}
element.style.borderColor = Util.makeCssRgb(rgb);
element.style.borderStyle = 'solid';
var width = rect[2] - rect[0] - 2 * borderWidth; var item = this.data;
var height = rect[3] - rect[1] - 2 * borderWidth; var rect = item.rect;
element.style.width = width + 'px';
element.style.height = height + 'px';
element.href = this.data.url || ''; container.style.borderColor = item.colorCssRgb;
return element; container.style.borderStyle = 'solid';
var link = document.createElement('a');
link.href = link.title = this.data.url || '';
container.appendChild(link);
return container;
} }
}); });

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns="http://www.w3.org/2000/svg"
width="40"
height="40"
viewBox="0 0 40 40">
</svg>

After

Width:  |  Height:  |  Size: 158 B

View File

@ -306,10 +306,13 @@ var PageView = function pageView(container, id, scale,
CustomStyle.setProp('transformOrigin', element, transformOriginStr); CustomStyle.setProp('transformOrigin', element, transformOriginStr);
if (data.subtype === 'Link' && !data.url) { if (data.subtype === 'Link' && !data.url) {
var link = element.getElementsByTagName('a')[0];
if (link) {
if (data.action) { if (data.action) {
bindNamedAction(element, data.action); bindNamedAction(link, data.action);
} else { } else {
bindLink(element, ('dest' in data) ? data.dest : null); bindLink(link, ('dest' in data) ? data.dest : null);
}
} }
} }
@ -579,6 +582,7 @@ var PageView = function pageView(container, id, scale,
canvasContext: ctx, canvasContext: ctx,
viewport: this.viewport, viewport: this.viewport,
textLayer: textLayer, textLayer: textLayer,
// intent: 'default', // === 'display'
continueCallback: function pdfViewcContinueCallback(cont) { continueCallback: function pdfViewcContinueCallback(cont) {
if (PDFView.highestPriorityPage !== 'page' + self.id) { if (PDFView.highestPriorityPage !== 'page' + self.id) {
self.renderingState = RenderingStates.PAUSED; self.renderingState = RenderingStates.PAUSED;
@ -650,13 +654,13 @@ var PageView = function pageView(container, id, scale,
var renderContext = { var renderContext = {
canvasContext: ctx, canvasContext: ctx,
viewport: viewport viewport: viewport,
intent: 'print'
}; };
pdfPage.render(renderContext).promise.then(function() { pdfPage.render(renderContext).promise.then(function() {
// Tell the printEngine that rendering this canvas/page has finished. // Tell the printEngine that rendering this canvas/page has finished.
obj.done(); obj.done();
self.pdfPage.destroy();
}, function(error) { }, function(error) {
console.error(error); console.error(error);
// Tell the printEngine that rendering this canvas/page has failed. // Tell the printEngine that rendering this canvas/page has failed.
@ -666,7 +670,6 @@ var PageView = function pageView(container, id, scale,
} else { } else {
obj.done(); obj.done();
} }
self.pdfPage.destroy();
}); });
}; };
}; };

View File

@ -1247,14 +1247,7 @@ canvas {
background-color: white; background-color: white;
} }
.page > a, .annotLink > a:hover {
.annotationLayer > a {
display: block;
position: absolute;
}
.page > a:hover,
.annotationLayer > a:hover {
opacity: 0.2; opacity: 0.2;
background: #ff0; background: #ff0;
box-shadow: 0px 2px 10px #ff0; box-shadow: 0px 2px 10px #ff0;
@ -1319,29 +1312,49 @@ canvas {
::selection { background:rgba(0,0,255,0.3); } ::selection { background:rgba(0,0,255,0.3); }
::-moz-selection { background:rgba(0,0,255,0.3); } ::-moz-selection { background:rgba(0,0,255,0.3); }
.annotText > div { .annotationHighlight {
z-index: 200;
position: absolute; position: absolute;
padding: 0.6em; border: 2px #FFFF99 solid;
max-width: 20em;
background-color: #FFFF99;
box-shadow: 0px 2px 10px #333;
border-radius: 7px;
} }
.annotText > img { .annotText > img {
position: absolute; position: absolute;
opacity: 0.6; cursor: pointer;
} }
.annotText > img:hover { .annotTextContentWrapper {
opacity: 1; position: absolute;
width: 20em;
} }
.annotText > div > h1 { .annotTextContent {
font-size: 1.2em; z-index: 200;
float: left;
max-width: 20em;
background-color: #FFFF99;
box-shadow: 0px 2px 5px #333;
border-radius: 2px;
padding: 0.6em;
cursor: pointer;
}
.annotTextContent > h1 {
font-size: 1em;
border-bottom: 1px solid #000000; border-bottom: 1px solid #000000;
margin: 0px; padding-bottom: 0.2em;
}
.annotTextContent > p {
padding-top: 0.2em;
}
.annotLink > a {
position: absolute;
font-size: 1em;
top: 0;
left: 0;
width: 100%;
height: 100%;
} }
#errorWrapper { #errorWrapper {