Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Basic AcroForms input controls rendering #6172

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 12 additions & 2 deletions src/core/annotation.js
Original file line number Diff line number Diff line change
Expand Up @@ -421,8 +421,17 @@ var Annotation = (function AnnotationClosure() {
annotations, opList, partialEvaluator, task, intent) {
var annotationPromises = [];
for (var i = 0, n = annotations.length; i < n; ++i) {
if ((intent === 'display' && annotations[i].viewable) ||
(intent === 'print' && annotations[i].printable)) {
// Always include for printing
var include = intent === 'print' && annotations[i].printable;
if (!include && intent === 'display' && annotations[i].viewable) {
var data = annotations[i].data;
// Don't render text widget annotation
// becuase they will be rendered by annotation layer.
if (annotations[i] instanceof TextWidgetAnnotation) {
include = false;
}
}
if (include) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

annotationPromises.push(
annotations[i].getOperatorList(partialEvaluator, task));
}
Expand Down Expand Up @@ -643,6 +652,7 @@ var TextWidgetAnnotation = (function TextWidgetAnnotationClosure() {
WidgetAnnotation.call(this, params);

this.data.textAlignment = Util.getInheritableProperty(params.dict, 'Q');
this.data.maxLen = Util.getInheritableProperty(params.dict, 'MaxLen');
}

Util.inherit(TextWidgetAnnotation, WidgetAnnotation, {
Expand Down
117 changes: 102 additions & 15 deletions src/display/annotation_layer.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ var CustomStyle = displayDOMUtils.CustomStyle;
* @property {PageViewport} viewport
* @property {IPDFLinkService} linkService
* @property {DownloadManager} downloadManager
* @property {IPDFStorageService} storageService
*/

/**
Expand All @@ -68,6 +69,13 @@ AnnotationElementFactory.prototype =
return new TextAnnotationElement(parameters);

case AnnotationType.WIDGET:
switch (parameters.data.fieldType) {
case 'Tx':
return new TextWidgetAnnotationElement(parameters);
}
warn('Unimplemented Widget annotation type: ' +
parameters.data.fieldType);
// Fallback to default one, which does not render anything.
return new WidgetAnnotationElement(parameters);

case AnnotationType.POPUP:
Expand Down Expand Up @@ -107,6 +115,7 @@ var AnnotationElement = (function AnnotationElementClosure() {
this.viewport = parameters.viewport;
this.linkService = parameters.linkService;
this.downloadManager = parameters.downloadManager;
this.storageService = parameters.storageService;

if (isRenderable) {
this.container = this._createContainer();
Expand Down Expand Up @@ -386,9 +395,7 @@ var TextAnnotationElement = (function TextAnnotationElementClosure() {
* @alias WidgetAnnotationElement
*/
var WidgetAnnotationElement = (function WidgetAnnotationElementClosure() {
function WidgetAnnotationElement(parameters) {
var isRenderable = !parameters.data.hasAppearance &&
!!parameters.data.fieldValue;
function WidgetAnnotationElement(parameters, isRenderable) {
AnnotationElement.call(this, parameters, isRenderable);
}

Expand All @@ -401,19 +408,94 @@ var WidgetAnnotationElement = (function WidgetAnnotationElementClosure() {
* @returns {HTMLSectionElement}
*/
render: function WidgetAnnotationElement_render() {
var content = document.createElement('div');
content.textContent = this.data.fieldValue;
return this.container;
},

/**
* Check bit value for given position in fieldFlags.
* Note: position is 1 based index.
*
* @private
* @memberof WidgetAnnotationElement
* @returns {boolean}
*/
_hasFlag: function WidgetAnnotationElement_hasFlag(position) {
return !!(this.data.fieldFlags & (1 << (position - 1)));
}
});

return WidgetAnnotationElement;
})();

/**
* @class
* @alias TextWidgetAnnotationElement
*/
var TextWidgetAnnotationElement =
(function TextWidgetAnnotationElementClosure() {

var READONLY_BIT = 1;
var MULTILINE_BIT = 13;

function TextWidgetAnnotationElement(parameters) {
WidgetAnnotationElement.call(this, parameters, true);
}

Util.inherit(TextWidgetAnnotationElement, WidgetAnnotationElement, {
/**
* Render the text widget annotation's HTML element.
*
* @public
* @memberof TextWidgetAnnotationElement
* @returns {HTMLSectionElement}
*/
render: function TextWidgetAnnotationElement_render() {
var container = WidgetAnnotationElement.prototype.render.call(this);

var isReadonly = this._hasFlag(READONLY_BIT);
var isMultiline = this._hasFlag(MULTILINE_BIT);

var content;
if (isMultiline) {
content = document.createElement('textarea');
} else {
content = document.createElement('input');
content.type = 'text';
}

content.disabled = isReadonly;
content.value = this.storageService.get(this.data.fullName) ||
this.data.fieldValue;
var textAlignment = this.data.textAlignment;
content.style.textAlign = ['left', 'center', 'right'][textAlignment];
content.style.verticalAlign = 'middle';
content.style.display = 'table-cell';
if (this.data.maxLen !== null) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would if (this.data.maxLen) { work too? I'm not sure if you need to explicitly mention !== null.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

0 is a valid maxLen

content.maxLength = this.data.maxLen;
}

var font = (this.data.fontRefName ?
this.page.commonObjs.getData(this.data.fontRefName) : null);
this._setTextStyle(content, font);

this.container.appendChild(content);
return this.container;
if (!isMultiline && !('fontSize' in this.data)) {
// Hack to guess font size based on content height
// so small text fields are rendered correctly.
// TODO: remove this when we can apply the default appearance.
var height = this.data.rect[3] - this.data.rect[1];
if (height < 15) {
content.style.fontSize = (height - 1) + 'px';
}
}

content.onchange = this._onchange.bind(this);

container.appendChild(content);

container.className = 'widgetAnnotation';
return container;
},

_onchange: function(evt) {
this.storageService.set(this.data.fullName, evt.target.value);
},

/**
Expand All @@ -422,14 +504,18 @@ var WidgetAnnotationElement = (function WidgetAnnotationElementClosure() {
* @private
* @param {HTMLDivElement} element
* @param {Object} font
* @memberof WidgetAnnotationElement
* @memberof TextWidgetAnnotationElement
*/
_setTextStyle:
function WidgetAnnotationElement_setTextStyle(element, font) {
function TextWidgetAnnotationElement_setTextStyle(element, font) {
// TODO: This duplicates some of the logic in CanvasGraphics.setFont().
var style = element.style;
style.fontSize = this.data.fontSize + 'px';
style.direction = (this.data.fontDirection < 0 ? 'rtl': 'ltr');
if ('fontSize' in this.data) {
style.fontSize = this.data.fontSize + 'px';
}
if ('fontDirection' in this.data) {
style.direction = (this.data.fontDirection < 0 ? 'rtl': 'ltr');
}

if (!font) {
return;
Expand All @@ -447,7 +533,7 @@ var WidgetAnnotationElement = (function WidgetAnnotationElementClosure() {
}
});

return WidgetAnnotationElement;
return TextWidgetAnnotationElement;
})();

/**
Expand Down Expand Up @@ -868,7 +954,8 @@ var AnnotationLayer = (function AnnotationLayerClosure() {
page: parameters.page,
viewport: parameters.viewport,
linkService: parameters.linkService,
downloadManager: parameters.downloadManager
downloadManager: parameters.downloadManager,
storageService: parameters.storageService
};
var element = annotationElementFactory.create(properties);
if (element.isRenderable) {
Expand Down
23 changes: 23 additions & 0 deletions web/annotation_layer_builder.css
Original file line number Diff line number Diff line change
Expand Up @@ -76,3 +76,26 @@
.annotationLayer .fileAttachmentAnnotation {
cursor: pointer;
}

.annotationLayer input[disabled], textarea[disabled] {
cursor: not-allowed;
}

.annotationLayer .widgetAnnotation > input[type='text'], textarea {
vertical-align: top;
}

.annotationLayer .widgetAnnotation textarea {
resize: none;
width: 100%;
height: 100%;
background: rgba(192, 192, 192, 0.2);
border: 0px none;
}

.annotationLayer .widgetAnnotation input[type='text'] {
width: 100%;
height: 100%;
background: rgba(192, 192, 192, 0.2);
border: 0px none;
}
8 changes: 6 additions & 2 deletions web/annotation_layer_builder.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*globals PDFJS, mozL10n, SimpleLinkService */
/*globals PDFJS, mozL10n, SimpleLinkService, SimpleStorageService */

'use strict';

Expand All @@ -22,6 +22,7 @@
* @property {PDFPage} pdfPage
* @property {IPDFLinkService} linkService
* @property {DownloadManager} downloadManager
* @property {IPDFStorageService} storageService
*/

/**
Expand All @@ -37,6 +38,7 @@ var AnnotationLayerBuilder = (function AnnotationLayerBuilderClosure() {
this.pdfPage = options.pdfPage;
this.linkService = options.linkService;
this.downloadManager = options.downloadManager;
this.storageService = options.storageService;

this.div = null;
}
Expand All @@ -62,7 +64,8 @@ var AnnotationLayerBuilder = (function AnnotationLayerBuilderClosure() {
annotations: annotations,
page: self.pdfPage,
linkService: self.linkService,
downloadManager: self.downloadManager
downloadManager: self.downloadManager,
storageService: self.storageService
};

if (self.div) {
Expand Down Expand Up @@ -116,6 +119,7 @@ DefaultAnnotationLayerFactory.prototype = {
pageDiv: pageDiv,
pdfPage: pdfPage,
linkService: new SimpleLinkService(),
storageService: new SimpleStorageService(),
});
}
};
11 changes: 11 additions & 0 deletions web/interfaces.js
Original file line number Diff line number Diff line change
Expand Up @@ -115,3 +115,14 @@ IPDFAnnotationLayerFactory.prototype = {
*/
createAnnotationLayerBuilder: function (pageDiv, pdfPage) {}
};

/**
* @interface
*/
function IPDFStorageService() {}
IPDFStorageService.prototype = {
get: function (key) {},
set: function (key, value) {},
remove: function (key) {},
removeAll: function () {},
};
28 changes: 27 additions & 1 deletion web/pdf_viewer.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ var DEFAULT_CACHE_SIZE = 10;
* @property {IPDFLinkService} linkService - The navigation/linking service.
* @property {DownloadManager} downloadManager - (optional) The download
* manager component.
* @property {IPDFStorageService} storageService - The storage service.
* @property {PDFRenderingQueue} renderingQueue - (optional) The rendering
* queue object.
* @property {boolean} removePageBorders - (optional) Removes the border shadow
Expand Down Expand Up @@ -95,6 +96,7 @@ var PDFViewer = (function pdfViewer() {
this.viewer = options.viewer || options.container.firstElementChild;
this.linkService = options.linkService || new SimpleLinkService();
this.downloadManager = options.downloadManager || null;
this.storageService = options.storageService || new SimpleStorageService();
this.removePageBorders = options.removePageBorders || false;

this.defaultRenderingQueue = !options.renderingQueue;
Expand Down Expand Up @@ -691,6 +693,7 @@ var PDFViewer = (function pdfViewer() {
this._pages[i].reset();
}
}
this.storageService.removeAll();
},

/**
Expand Down Expand Up @@ -761,7 +764,8 @@ var PDFViewer = (function pdfViewer() {
pageDiv: pageDiv,
pdfPage: pdfPage,
linkService: this.linkService,
downloadManager: this.downloadManager
downloadManager: this.downloadManager,
storageService: this.storageService
});
},

Expand Down Expand Up @@ -821,3 +825,25 @@ var SimpleLinkService = (function SimpleLinkServiceClosure() {
};
return SimpleLinkService;
})();

var SimpleStorageService = (function SimpleStorageServiceClosure() {
function SimpleStorageService() {
this._storage = Object.create(null);
}

SimpleStorageService.prototype = {
set: function(key, value) {
this._storage[key] = value;
},
get: function(key) {
return this._storage[name];
},
remove: function(key) {
delete this._storage[name];
},
removeAll: function(key) {
this._storage = Object.create(null);
}
};
return SimpleStorageService;
})();