Move the creation of canvas path fonts to the worker.
This commit is contained in:
parent
81c9eeef4b
commit
bb2529de03
@ -13,7 +13,6 @@
|
||||
<script type="text/javascript" src="../../src/display/metadata.js"></script>
|
||||
<script type="text/javascript" src="../../src/display/canvas.js"></script>
|
||||
<script type="text/javascript" src="../../src/display/font_loader.js"></script>
|
||||
<script type="text/javascript" src="../../src/display/font_renderer.js"></script>
|
||||
|
||||
<script type="text/javascript">
|
||||
// Specify the main script used to create a new PDF.JS web worker.
|
||||
|
@ -13,7 +13,6 @@
|
||||
<script type="text/javascript" src="../../src/display/metadata.js"></script>
|
||||
<script type="text/javascript" src="../../src/display/canvas.js"></script>
|
||||
<script type="text/javascript" src="../../src/display/font_loader.js"></script>
|
||||
<script type="text/javascript" src="../../src/display/font_renderer.js"></script>
|
||||
|
||||
<script type="text/javascript">
|
||||
// Specify the main script used to create a new PDF.JS web worker.
|
||||
|
4
make.js
4
make.js
@ -278,8 +278,7 @@ target.bundle = function(args) {
|
||||
'display/api.js',
|
||||
'display/metadata.js',
|
||||
'display/canvas.js',
|
||||
'display/font_loader.js',
|
||||
'display/font_renderer.js'
|
||||
'display/font_loader.js'
|
||||
];
|
||||
|
||||
var WORKER_SRC_FILES = [
|
||||
@ -298,6 +297,7 @@ target.bundle = function(args) {
|
||||
'core/crypto.js',
|
||||
'core/evaluator.js',
|
||||
'core/fonts.js',
|
||||
'core/font_renderer.js',
|
||||
'core/glyphlist.js',
|
||||
'core/image.js',
|
||||
'core/metrics.js',
|
||||
|
@ -20,7 +20,7 @@
|
||||
isStream, isString, JpegStream, Lexer, Metrics, Name, Parser,
|
||||
Pattern, PDFImage, PDFJS, serifFonts, stdFontMap, symbolsFonts,
|
||||
TilingPattern, TODO, warn, Util, Promise,
|
||||
RefSetCache, isRef */
|
||||
RefSetCache, isRef, TextRenderingMode */
|
||||
|
||||
'use strict';
|
||||
|
||||
@ -349,6 +349,31 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
|
||||
return loadedName;
|
||||
},
|
||||
|
||||
handleText: function PartialEvaluator_handleText(chars) {
|
||||
var font = this.state.font.translated;
|
||||
var glyphs = font.charsToGlyphs(chars);
|
||||
var isAddToPathSet = !!(this.state.textRenderingMode &
|
||||
TextRenderingMode.ADD_TO_PATH_FLAG);
|
||||
if (isAddToPathSet || PDFJS.disableFontFace) {
|
||||
for (var i = 0; i < glyphs.length; i++) {
|
||||
if (glyphs[i] === null) {
|
||||
continue;
|
||||
}
|
||||
var fontChar = glyphs[i].fontChar;
|
||||
if (!font.renderer.hasBuiltPath(fontChar)) {
|
||||
var path = font.renderer.getPathJs(fontChar);
|
||||
this.handler.send('commonobj', [
|
||||
font.loadedName + '_path_' + fontChar,
|
||||
'FontPath',
|
||||
path
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return glyphs;
|
||||
},
|
||||
|
||||
setGState: function PartialEvaluator_setGState(resources, gState,
|
||||
operatorList) {
|
||||
|
||||
@ -631,19 +656,21 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
|
||||
this.state = prev;
|
||||
}
|
||||
} else if (cmd === 'Tj') { // showText
|
||||
args[0] = this.state.font.translated.charsToGlyphs(args[0]);
|
||||
args[0] = this.handleText(args[0]);
|
||||
} else if (cmd === 'TJ') { // showSpacedText
|
||||
var arr = args[0];
|
||||
var arrLength = arr.length;
|
||||
for (var i = 0; i < arrLength; ++i) {
|
||||
if (isString(arr[i])) {
|
||||
arr[i] = this.state.font.translated.charsToGlyphs(arr[i]);
|
||||
arr[i] = this.handleText(arr[i]);
|
||||
}
|
||||
}
|
||||
} else if (cmd === '\'') { // nextLineShowText
|
||||
args[0] = this.state.font.translated.charsToGlyphs(args[0]);
|
||||
args[0] = this.handleText(args[0]);
|
||||
} else if (cmd === '"') { // nextLineSetSpacingShowText
|
||||
args[2] = this.state.font.translated.charsToGlyphs(args[2]);
|
||||
args[2] = this.handleText(args[2]);
|
||||
} else if (cmd === 'Tr') { // setTextRenderingMode
|
||||
this.state.textRenderingMode = args[0];
|
||||
}
|
||||
|
||||
switch (fn) {
|
||||
@ -1529,6 +1556,7 @@ var OperatorList = (function OperatorListClosure() {
|
||||
var EvalState = (function EvalStateClosure() {
|
||||
function EvalState() {
|
||||
this.font = null;
|
||||
this.textRenderingMode = TextRenderingMode.FILL;
|
||||
}
|
||||
EvalState.prototype = {
|
||||
clone: function CanvasExtraState_clone() {
|
||||
|
@ -14,7 +14,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/* globals error, Stream, GlyphsUnicode, CFFParser, Encodings */
|
||||
/* globals error, Stream, GlyphsUnicode, CFFParser, Encodings, Util */
|
||||
|
||||
'use strict';
|
||||
|
||||
@ -585,18 +585,14 @@ var FontRendererFactory = (function FontRendererFactoryClosure() {
|
||||
parse(code);
|
||||
}
|
||||
|
||||
function TrueTypeCompiled(glyphs, cmap, fontMatrix) {
|
||||
this.glyphs = glyphs;
|
||||
this.cmap = cmap;
|
||||
this.fontMatrix = fontMatrix || [0.000488, 0, 0, 0.000488, 0, 0];
|
||||
var noop = '';
|
||||
|
||||
this.compiledGlyphs = [];
|
||||
function CompiledFont(fontMatrix) {
|
||||
this.compiledGlyphs = {};
|
||||
this.fontMatrix = fontMatrix;
|
||||
}
|
||||
|
||||
var noop = function () {};
|
||||
|
||||
TrueTypeCompiled.prototype = {
|
||||
getPathGenerator: function (unicode) {
|
||||
CompiledFont.prototype = {
|
||||
getPathJs: function (unicode) {
|
||||
var gid = lookupCmap(this.cmap, unicode);
|
||||
var fn = this.compiledGlyphs[gid];
|
||||
if (!fn) {
|
||||
@ -604,6 +600,7 @@ var FontRendererFactory = (function FontRendererFactoryClosure() {
|
||||
}
|
||||
return fn;
|
||||
},
|
||||
|
||||
compileGlyph: function (code) {
|
||||
if (!code || code.length === 0 || code[0] === 14) {
|
||||
return noop;
|
||||
@ -614,23 +611,47 @@ var FontRendererFactory = (function FontRendererFactoryClosure() {
|
||||
js.push('c.transform(' + this.fontMatrix.join(',') + ');');
|
||||
js.push('c.scale(size, -size);');
|
||||
|
||||
var stack = [], x = 0, y = 0;
|
||||
compileGlyf(code, js, this);
|
||||
this.compileGlyphImpl(code, js);
|
||||
|
||||
js.push('c.restore();');
|
||||
|
||||
/*jshint -W054 */
|
||||
return new Function('c', 'size', js.join('\n'));
|
||||
return js.join('\n');
|
||||
},
|
||||
|
||||
compileGlyphImpl: function () {
|
||||
error('Children classes should implement this.');
|
||||
},
|
||||
|
||||
hasBuiltPath: function (unicode) {
|
||||
var gid = lookupCmap(this.cmap, unicode);
|
||||
return gid in this.compiledGlyphs;
|
||||
}
|
||||
};
|
||||
|
||||
function TrueTypeCompiled(glyphs, cmap, fontMatrix) {
|
||||
fontMatrix = fontMatrix || [0.000488, 0, 0, 0.000488, 0, 0];
|
||||
CompiledFont.call(this, fontMatrix);
|
||||
|
||||
this.glyphs = glyphs;
|
||||
this.cmap = cmap;
|
||||
|
||||
this.compiledGlyphs = [];
|
||||
}
|
||||
|
||||
Util.inherit(TrueTypeCompiled, CompiledFont, {
|
||||
compileGlyphImpl: function (code, js) {
|
||||
compileGlyf(code, js, this);
|
||||
}
|
||||
});
|
||||
|
||||
function Type2Compiled(cffInfo, cmap, fontMatrix, glyphNameMap) {
|
||||
fontMatrix = fontMatrix || [0.001, 0, 0, 0.001, 0, 0];
|
||||
CompiledFont.call(this, fontMatrix);
|
||||
this.glyphs = cffInfo.glyphs;
|
||||
this.gsubrs = cffInfo.gsubrs || [];
|
||||
this.subrs = cffInfo.subrs || [];
|
||||
this.cmap = cmap;
|
||||
this.glyphNameMap = glyphNameMap || GlyphsUnicode;
|
||||
this.fontMatrix = fontMatrix || [0.001, 0, 0, 0.001, 0, 0];
|
||||
|
||||
this.compiledGlyphs = [];
|
||||
this.gsubrsBias = this.gsubrs.length < 1240 ? 107 :
|
||||
@ -639,34 +660,12 @@ var FontRendererFactory = (function FontRendererFactoryClosure() {
|
||||
this.subrs.length < 33900 ? 1131 : 32768;
|
||||
}
|
||||
|
||||
Type2Compiled.prototype = {
|
||||
getPathGenerator: function (unicode) {
|
||||
var gid = lookupCmap(this.cmap, unicode);
|
||||
var fn = this.compiledGlyphs[gid];
|
||||
if (!fn) {
|
||||
this.compiledGlyphs[gid] = fn = this.compileGlyph(this.glyphs[gid]);
|
||||
}
|
||||
return fn;
|
||||
},
|
||||
compileGlyph: function (code) {
|
||||
if (!code || code.length === 0 || code[0] === 14) {
|
||||
return noop;
|
||||
}
|
||||
|
||||
var js = [];
|
||||
js.push('c.save();');
|
||||
js.push('c.transform(' + this.fontMatrix.join(',') + ');');
|
||||
js.push('c.scale(size, -size);');
|
||||
|
||||
var stack = [], x = 0, y = 0;
|
||||
Util.inherit(Type2Compiled, CompiledFont, {
|
||||
compileGlyphImpl: function (code, js) {
|
||||
compileCharString(code, js, this);
|
||||
|
||||
js.push('c.restore();');
|
||||
|
||||
/*jshint -W054 */
|
||||
return new Function('c', 'size', js.join('\n'));
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
|
||||
return {
|
||||
create: function FontRendererFactory_create(font) {
|
@ -18,7 +18,7 @@
|
||||
ExpertSubsetCharset, FileReaderSync, GlyphsUnicode,
|
||||
info, isArray, isNum, ISOAdobeCharset, Stream,
|
||||
stringToBytes, TextDecoder, TODO, warn, Lexer, Util,
|
||||
FONT_IDENTITY_MATRIX */
|
||||
FONT_IDENTITY_MATRIX, FontRendererFactory, shadow */
|
||||
|
||||
'use strict';
|
||||
|
||||
@ -2791,6 +2791,10 @@ var Font = (function FontClosure() {
|
||||
font: null,
|
||||
mimetype: null,
|
||||
encoding: null,
|
||||
get renderer() {
|
||||
var renderer = FontRendererFactory.create(this);
|
||||
return shadow(this, 'renderer', renderer);
|
||||
},
|
||||
|
||||
exportData: function Font_exportData() {
|
||||
var data = {};
|
||||
|
@ -224,6 +224,7 @@ var WorkerMessageHandler = PDFJS.WorkerMessageHandler = {
|
||||
|
||||
PDFJS.maxImageSize = data.maxImageSize === undefined ?
|
||||
-1 : data.maxImageSize;
|
||||
PDFJS.disableFontFace = data.disableFontFace;
|
||||
|
||||
getPdfManager(data).then(function pdfManagerReady() {
|
||||
loadDocument(false).then(onSuccess, function loadFailure(ex) {
|
||||
|
@ -29,6 +29,16 @@
|
||||
*/
|
||||
PDFJS.maxImageSize = PDFJS.maxImageSize === undefined ? -1 : PDFJS.maxImageSize;
|
||||
|
||||
/**
|
||||
* By default fonts are converted to OpenType fonts and loaded via font face
|
||||
* rules. If disabled, the font will be rendered using a built in font renderer
|
||||
* that constructs the glyphs with primitive path commands.
|
||||
* @var {Boolean}
|
||||
*/
|
||||
PDFJS.disableFontFace = PDFJS.disableFontFace === undefined ?
|
||||
false :
|
||||
PDFJS.disableFontFace;
|
||||
|
||||
/**
|
||||
* This is the main entry point for loading a PDF and interacting with it.
|
||||
* NOTE: If a URL is used to fetch the PDF data a standard XMLHttpRequest(XHR)
|
||||
@ -673,6 +683,9 @@ var WorkerTransport = (function WorkerTransportClosure() {
|
||||
}.bind(this)
|
||||
);
|
||||
break;
|
||||
case 'FontPath':
|
||||
this.commonObjs.resolve(id, data[2]);
|
||||
break;
|
||||
default:
|
||||
error('Got unknown common object type ' + type);
|
||||
}
|
||||
@ -770,7 +783,8 @@ var WorkerTransport = (function WorkerTransportClosure() {
|
||||
this.messageHandler.send('GetDocRequest', {
|
||||
source: source,
|
||||
disableRange: PDFJS.disableRange,
|
||||
maxImageSize: PDFJS.maxImageSize
|
||||
maxImageSize: PDFJS.maxImageSize,
|
||||
disableFontFace: PDFJS.disableFontFace
|
||||
});
|
||||
},
|
||||
|
||||
|
@ -16,26 +16,14 @@
|
||||
*/
|
||||
/* globals ColorSpace, DeviceCmykCS, DeviceGrayCS, DeviceRgbCS, error,
|
||||
FONT_IDENTITY_MATRIX, IDENTITY_MATRIX, ImageData, isArray, isNum,
|
||||
Pattern, TilingPattern, TODO, Util, warn, assert, info */
|
||||
Pattern, TilingPattern, TODO, Util, warn, assert, info,
|
||||
TextRenderingMode */
|
||||
|
||||
'use strict';
|
||||
|
||||
// <canvas> contexts store most of the state we need natively.
|
||||
// However, PDF needs a bit more state, which we store here.
|
||||
|
||||
var TextRenderingMode = {
|
||||
FILL: 0,
|
||||
STROKE: 1,
|
||||
FILL_STROKE: 2,
|
||||
INVISIBLE: 3,
|
||||
FILL_ADD_TO_PATH: 4,
|
||||
STROKE_ADD_TO_PATH: 5,
|
||||
FILL_STROKE_ADD_TO_PATH: 6,
|
||||
ADD_TO_PATH: 7,
|
||||
FILL_STROKE_MASK: 3,
|
||||
ADD_TO_PATH_FLAG: 4
|
||||
};
|
||||
|
||||
// Minimal font size that would be used during canvas fillText operations.
|
||||
var MIN_FONT_SIZE = 16;
|
||||
|
||||
@ -1007,7 +995,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
|
||||
|
||||
var addToPath;
|
||||
if (font.disableFontFace || isAddToPathSet) {
|
||||
addToPath = font.renderer.getPathGenerator(character);
|
||||
addToPath = font.getPathGenerator(this.commonObjs, character);
|
||||
}
|
||||
|
||||
if (font.disableFontFace) {
|
||||
|
@ -14,8 +14,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/* globals PDFJS, shadow, isWorker, assert, warn, FontRendererFactory,
|
||||
bytesToString, globalScope */
|
||||
/* globals PDFJS, shadow, isWorker, assert, warn, bytesToString, globalScope */
|
||||
|
||||
'use strict';
|
||||
|
||||
@ -267,6 +266,7 @@ var FontLoader = {
|
||||
|
||||
var FontFace = (function FontFaceClosure() {
|
||||
function FontFace(name, file, properties) {
|
||||
this.compiledGlyphs = {};
|
||||
if (arguments.length === 1) {
|
||||
// importing translated data
|
||||
var data = arguments[0];
|
||||
@ -277,10 +277,6 @@ var FontFace = (function FontFaceClosure() {
|
||||
}
|
||||
}
|
||||
FontFace.prototype = {
|
||||
get renderer() {
|
||||
var renderer = FontRendererFactory.create(this);
|
||||
return shadow(this, 'renderer', renderer);
|
||||
},
|
||||
bindDOM: function FontFace_bindDOM() {
|
||||
if (!this.data)
|
||||
return null;
|
||||
@ -305,6 +301,14 @@ var FontFace = (function FontFaceClosure() {
|
||||
globalScope['FontInspector'].fontAdded(this, url);
|
||||
|
||||
return rule;
|
||||
},
|
||||
getPathGenerator: function (objs, character) {
|
||||
if (!(character in this.compiledGlyphs)) {
|
||||
var js = objs.get(this.loadedName + '_path_' + character);
|
||||
/*jshint -W054 */
|
||||
this.compiledGlyphs[character] = new Function('c', 'size', js);
|
||||
}
|
||||
return this.compiledGlyphs[character];
|
||||
}
|
||||
};
|
||||
return FontFace;
|
||||
|
@ -27,6 +27,19 @@ var verbosity = WARNINGS;
|
||||
|
||||
var FONT_IDENTITY_MATRIX = [0.001, 0, 0, 0.001, 0, 0];
|
||||
|
||||
var TextRenderingMode = {
|
||||
FILL: 0,
|
||||
STROKE: 1,
|
||||
FILL_STROKE: 2,
|
||||
INVISIBLE: 3,
|
||||
FILL_ADD_TO_PATH: 4,
|
||||
STROKE_ADD_TO_PATH: 5,
|
||||
FILL_STROKE_ADD_TO_PATH: 6,
|
||||
ADD_TO_PATH: 7,
|
||||
FILL_STROKE_MASK: 3,
|
||||
ADD_TO_PATH_FLAG: 4
|
||||
};
|
||||
|
||||
// The global PDFJS object exposes the API
|
||||
// In production, it will be declared outside a global wrapper
|
||||
// In development, it will be declared here
|
||||
|
@ -35,6 +35,7 @@ var files = [
|
||||
'core/crypto.js',
|
||||
'core/evaluator.js',
|
||||
'core/fonts.js',
|
||||
'core/font_renderer.js',
|
||||
'core/glyphlist.js',
|
||||
'core/image.js',
|
||||
'core/metrics.js',
|
||||
|
BIN
test/pdfs/issue3584.pdf
Normal file
BIN
test/pdfs/issue3584.pdf
Normal file
Binary file not shown.
@ -1063,6 +1063,13 @@
|
||||
"link": true,
|
||||
"type": "eq"
|
||||
},
|
||||
{ "id": "issue3584",
|
||||
"file": "pdfs/issue3584.pdf",
|
||||
"md5": "7a00646865a840eefc76f05c588b60ce",
|
||||
"rounds": 1,
|
||||
"type": "eq",
|
||||
"about": "CFF font that is drawn with clipping."
|
||||
},
|
||||
{ "id": "annotation-tx",
|
||||
"file": "pdfs/annotation-tx.pdf",
|
||||
"md5": "56321ea830be9c4f8437ca17ac535b2d",
|
||||
|
@ -28,7 +28,6 @@ limitations under the License.
|
||||
<script type="text/javascript" src="/src/display/metadata.js"></script>
|
||||
<script type="text/javascript" src="/src/display/canvas.js"></script>
|
||||
<script type="text/javascript" src="/src/display/font_loader.js"></script>
|
||||
<script type="text/javascript" src="/src/display/font_renderer.js"></script>
|
||||
<script type="text/javascript" src="driver.js"></script>
|
||||
|
||||
<script type="text/javascript">
|
||||
|
@ -50,7 +50,6 @@ limitations under the License.
|
||||
<script type="text/javascript" src="../src/display/metadata.js"></script>
|
||||
<script type="text/javascript" src="../src/display/canvas.js"></script>
|
||||
<script type="text/javascript" src="../src/display/font_loader.js"></script>
|
||||
<script type="text/javascript" src="../src/display/font_renderer.js"></script>
|
||||
<script type="text/javascript">PDFJS.workerSrc = '../src/worker_loader.js';</script>
|
||||
<!--#endif-->
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user