Drawing without fillText; refactoring ADD_TO_PATH
This commit is contained in:
parent
67eb3bbc68
commit
0e133f0090
1
make.js
1
make.js
@ -247,6 +247,7 @@ target.bundle = function(args) {
|
|||||||
'crypto.js',
|
'crypto.js',
|
||||||
'evaluator.js',
|
'evaluator.js',
|
||||||
'fonts.js',
|
'fonts.js',
|
||||||
|
'font_renderer.js',
|
||||||
'glyphlist.js',
|
'glyphlist.js',
|
||||||
'image.js',
|
'image.js',
|
||||||
'metrics.js',
|
'metrics.js',
|
||||||
|
172
src/canvas.js
172
src/canvas.js
@ -32,6 +32,7 @@ var TextRenderingMode = {
|
|||||||
STROKE_ADD_TO_PATH: 5,
|
STROKE_ADD_TO_PATH: 5,
|
||||||
FILL_STROKE_ADD_TO_PATH: 6,
|
FILL_STROKE_ADD_TO_PATH: 6,
|
||||||
ADD_TO_PATH: 7,
|
ADD_TO_PATH: 7,
|
||||||
|
FILL_STROKE_MASK: 3,
|
||||||
ADD_TO_PATH_FLAG: 4
|
ADD_TO_PATH_FLAG: 4
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -632,10 +633,6 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
|
|||||||
this.current = old.clone();
|
this.current = old.clone();
|
||||||
},
|
},
|
||||||
restore: function CanvasGraphics_restore() {
|
restore: function CanvasGraphics_restore() {
|
||||||
if ('textClipLayers' in this) {
|
|
||||||
this.completeTextClipping();
|
|
||||||
}
|
|
||||||
|
|
||||||
var prev = this.stateStack.pop();
|
var prev = this.stateStack.pop();
|
||||||
if (prev) {
|
if (prev) {
|
||||||
this.current = prev;
|
this.current = prev;
|
||||||
@ -783,64 +780,25 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
|
|||||||
this.current.y = this.current.lineY = 0;
|
this.current.y = this.current.lineY = 0;
|
||||||
},
|
},
|
||||||
endText: function CanvasGraphics_endText() {
|
endText: function CanvasGraphics_endText() {
|
||||||
if ('textClipLayers' in this) {
|
if (!('pendingTextPaths' in this)) {
|
||||||
this.swapImageForTextClipping();
|
this.ctx.beginPath();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
},
|
var paths = this.pendingTextPaths;
|
||||||
getCurrentTextClipping: function CanvasGraphics_getCurrentTextClipping() {
|
|
||||||
var ctx = this.ctx;
|
var ctx = this.ctx;
|
||||||
var transform = ctx.mozCurrentTransform;
|
|
||||||
if ('textClipLayers' in this) {
|
ctx.save();
|
||||||
// we need to reset only font and transform
|
ctx.beginPath();
|
||||||
var maskCtx = this.textClipLayers.maskCtx;
|
for (var i = 0; i < paths.length; i++) {
|
||||||
maskCtx.setTransform.apply(maskCtx, transform);
|
var path = paths[i];
|
||||||
maskCtx.font = ctx.font;
|
ctx.setTransform.apply(ctx, path.transform);
|
||||||
return maskCtx;
|
ctx.translate(path.x, path.y);
|
||||||
|
path.addToPath(ctx, path.fontSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
var canvasWidth = ctx.canvas.width;
|
|
||||||
var canvasHeight = ctx.canvas.height;
|
|
||||||
// keeping track of the text clipping of the separate canvas
|
|
||||||
var maskCanvas = createScratchCanvas(canvasWidth, canvasHeight);
|
|
||||||
var maskCtx = maskCanvas.getContext('2d');
|
|
||||||
maskCtx.setTransform.apply(maskCtx, transform);
|
|
||||||
maskCtx.font = ctx.font;
|
|
||||||
var textClipLayers = {
|
|
||||||
maskCanvas: maskCanvas,
|
|
||||||
maskCtx: maskCtx
|
|
||||||
};
|
|
||||||
this.textClipLayers = textClipLayers;
|
|
||||||
return maskCtx;
|
|
||||||
},
|
|
||||||
swapImageForTextClipping:
|
|
||||||
function CanvasGraphics_swapImageForTextClipping() {
|
|
||||||
var ctx = this.ctx;
|
|
||||||
var canvasWidth = ctx.canvas.width;
|
|
||||||
var canvasHeight = ctx.canvas.height;
|
|
||||||
// saving current image content and clearing whole canvas
|
|
||||||
ctx.save();
|
|
||||||
ctx.setTransform(1, 0, 0, 1, 0, 0);
|
|
||||||
var data = ctx.getImageData(0, 0, canvasWidth, canvasHeight);
|
|
||||||
this.textClipLayers.imageData = data;
|
|
||||||
ctx.clearRect(0, 0, canvasWidth, canvasHeight);
|
|
||||||
ctx.restore();
|
ctx.restore();
|
||||||
},
|
ctx.clip();
|
||||||
completeTextClipping: function CanvasGraphics_completeTextClipping() {
|
ctx.beginPath();
|
||||||
var ctx = this.ctx;
|
delete this.pendingTextPaths;
|
||||||
// applying mask to the image (result is saved in maskCanvas)
|
|
||||||
var maskCtx = this.textClipLayers.maskCtx;
|
|
||||||
maskCtx.setTransform(1, 0, 0, 1, 0, 0);
|
|
||||||
maskCtx.globalCompositeOperation = 'source-in';
|
|
||||||
maskCtx.drawImage(ctx.canvas, 0, 0);
|
|
||||||
|
|
||||||
// restoring image data and applying the result of masked drawing
|
|
||||||
ctx.save();
|
|
||||||
ctx.setTransform(1, 0, 0, 1, 0, 0);
|
|
||||||
ctx.putImageData(this.textClipLayers.imageData, 0, 0);
|
|
||||||
ctx.drawImage(this.textClipLayers.maskCanvas, 0, 0);
|
|
||||||
ctx.restore();
|
|
||||||
|
|
||||||
delete this.textClipLayers;
|
|
||||||
},
|
},
|
||||||
setCharSpacing: function CanvasGraphics_setCharSpacing(spacing) {
|
setCharSpacing: function CanvasGraphics_setCharSpacing(spacing) {
|
||||||
this.current.charSpacing = spacing;
|
this.current.charSpacing = spacing;
|
||||||
@ -958,6 +916,59 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
|
|||||||
return geometry;
|
return geometry;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
paintChar: function (character, x, y) {
|
||||||
|
var ctx = this.ctx;
|
||||||
|
var current = this.current;
|
||||||
|
var font = current.font;
|
||||||
|
var fontSize = current.fontSize / current.fontSizeScale;
|
||||||
|
var textRenderingMode = current.textRenderingMode;
|
||||||
|
var fillStrokeMode = textRenderingMode &
|
||||||
|
TextRenderingMode.FILL_STROKE_MASK;
|
||||||
|
var isAddToPathSet = !!(textRenderingMode &
|
||||||
|
TextRenderingMode.ADD_TO_PATH_FLAG);
|
||||||
|
|
||||||
|
var addToPath;
|
||||||
|
if (font.disableFontFace || isAddToPathSet) {
|
||||||
|
addToPath = font.renderer.getPathGenerator(character);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (font.disableFontFace) {
|
||||||
|
ctx.save();
|
||||||
|
ctx.translate(x, y);
|
||||||
|
ctx.beginPath();
|
||||||
|
addToPath(ctx, fontSize);
|
||||||
|
if (fillStrokeMode === TextRenderingMode.FILL ||
|
||||||
|
fillStrokeMode === TextRenderingMode.FILL_STROKE) {
|
||||||
|
ctx.fill();
|
||||||
|
}
|
||||||
|
if (fillStrokeMode === TextRenderingMode.STROKE ||
|
||||||
|
fillStrokeMode === TextRenderingMode.FILL_STROKE) {
|
||||||
|
ctx.stroke();
|
||||||
|
}
|
||||||
|
ctx.restore();
|
||||||
|
} else {
|
||||||
|
if (fillStrokeMode === TextRenderingMode.FILL ||
|
||||||
|
fillStrokeMode === TextRenderingMode.FILL_STROKE) {
|
||||||
|
ctx.fillText(character, x, y);
|
||||||
|
}
|
||||||
|
if (fillStrokeMode === TextRenderingMode.STROKE ||
|
||||||
|
fillStrokeMode === TextRenderingMode.FILL_STROKE) {
|
||||||
|
ctx.strokeText(character, x, y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isAddToPathSet) {
|
||||||
|
var paths = this.pendingTextPaths || (this.pendingTextPaths = []);
|
||||||
|
paths.push({
|
||||||
|
transform: ctx.mozCurrentTransform,
|
||||||
|
x: x,
|
||||||
|
y: y,
|
||||||
|
fontSize: fontSize,
|
||||||
|
addToPath: addToPath
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
showText: function CanvasGraphics_showText(str, skipTextSelection) {
|
showText: function CanvasGraphics_showText(str, skipTextSelection) {
|
||||||
var ctx = this.ctx;
|
var ctx = this.ctx;
|
||||||
var current = this.current;
|
var current = this.current;
|
||||||
@ -973,7 +984,6 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
|
|||||||
var textLayer = this.textLayer;
|
var textLayer = this.textLayer;
|
||||||
var geom;
|
var geom;
|
||||||
var textSelection = textLayer && !skipTextSelection ? true : false;
|
var textSelection = textLayer && !skipTextSelection ? true : false;
|
||||||
var textRenderingMode = current.textRenderingMode;
|
|
||||||
var canvasWidth = 0.0;
|
var canvasWidth = 0.0;
|
||||||
var vertical = font.vertical;
|
var vertical = font.vertical;
|
||||||
var defaultVMetrics = font.defaultVMetrics;
|
var defaultVMetrics = font.defaultVMetrics;
|
||||||
@ -1071,10 +1081,6 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
|
|||||||
scaledX = x / fontSizeScale;
|
scaledX = x / fontSizeScale;
|
||||||
scaledY = 0;
|
scaledY = 0;
|
||||||
}
|
}
|
||||||
if (accent) {
|
|
||||||
scaledAccentX = scaledX + accent.offset.x / fontSizeScale;
|
|
||||||
scaledAccentY = scaledY - accent.offset.y / fontSizeScale;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (font.remeasure && width > 0) {
|
if (font.remeasure && width > 0) {
|
||||||
// some standard fonts may not have the exact width, trying to
|
// some standard fonts may not have the exact width, trying to
|
||||||
@ -1091,41 +1097,11 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (textRenderingMode) {
|
this.paintChar(character, scaledX, scaledY);
|
||||||
default: // other unsupported rendering modes
|
if (accent) {
|
||||||
case TextRenderingMode.FILL:
|
scaledAccentX = scaledX + accent.offset.x / fontSizeScale;
|
||||||
case TextRenderingMode.FILL_ADD_TO_PATH:
|
scaledAccentY = scaledY - accent.offset.y / fontSizeScale;
|
||||||
ctx.fillText(character, scaledX, scaledY);
|
this.paintChar(accent.fontChar, scaledAccentX, scaledAccentY);
|
||||||
if (accent) {
|
|
||||||
ctx.fillText(accent.fontChar, scaledAccentX, scaledAccentY);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case TextRenderingMode.STROKE:
|
|
||||||
case TextRenderingMode.STROKE_ADD_TO_PATH:
|
|
||||||
ctx.strokeText(character, scaledX, scaledY);
|
|
||||||
if (accent) {
|
|
||||||
ctx.strokeText(accent.fontChar, scaledAccentX, scaledAccentY);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case TextRenderingMode.FILL_STROKE:
|
|
||||||
case TextRenderingMode.FILL_STROKE_ADD_TO_PATH:
|
|
||||||
ctx.fillText(character, scaledX, scaledY);
|
|
||||||
ctx.strokeText(character, scaledX, scaledY);
|
|
||||||
if (accent) {
|
|
||||||
ctx.fillText(accent.fontChar, scaledAccentX, scaledAccentY);
|
|
||||||
ctx.strokeText(accent.fontChar, scaledAccentX, scaledAccentY);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case TextRenderingMode.INVISIBLE:
|
|
||||||
case TextRenderingMode.ADD_TO_PATH:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (textRenderingMode & TextRenderingMode.ADD_TO_PATH_FLAG) {
|
|
||||||
var clipCtx = this.getCurrentTextClipping();
|
|
||||||
clipCtx.fillText(character, scaledX, scaledY);
|
|
||||||
if (accent) {
|
|
||||||
clipCtx.fillText(accent.fontChar, scaledAccentX, scaledAccentY);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
711
src/font_renderer.js
Normal file
711
src/font_renderer.js
Normal file
@ -0,0 +1,711 @@
|
|||||||
|
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||||
|
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
|
||||||
|
/* Copyright 2012 Mozilla Foundation
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
/* globals error, Stream, GlyphsUnicode, CFFParser, Encodings */
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var FontRendererFactory = (function FontRendererFactoryClosure() {
|
||||||
|
function getLong(data, offset) {
|
||||||
|
return (data[offset] << 24) | (data[offset + 1] << 16) |
|
||||||
|
(data[offset + 2] << 8) | data[offset + 3];
|
||||||
|
}
|
||||||
|
|
||||||
|
function getUshort(data, offset) {
|
||||||
|
return (data[offset] << 8) | data[offset + 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseCmap(data, start, end) {
|
||||||
|
var offset = getUshort(data, start + 2) === 1 ? getLong(data, start + 8) :
|
||||||
|
getLong(data, start + 16);
|
||||||
|
var format = getUshort(data, start + offset);
|
||||||
|
if (format === 4) {
|
||||||
|
var length = getUshort(data, start + offset + 2);
|
||||||
|
var segCount = getUshort(data, start + offset + 6) >> 1;
|
||||||
|
var p = start + offset + 14;
|
||||||
|
var ranges = [];
|
||||||
|
for (var i = 0; i < segCount; i++, p += 2) {
|
||||||
|
ranges[i] = {end: getUshort(data, p)};
|
||||||
|
}
|
||||||
|
p += 2;
|
||||||
|
for (var i = 0; i < segCount; i++, p += 2) {
|
||||||
|
ranges[i].start = getUshort(data, p);
|
||||||
|
}
|
||||||
|
for (var i = 0; i < segCount; i++, p += 2) {
|
||||||
|
ranges[i].idDelta = getUshort(data, p);
|
||||||
|
}
|
||||||
|
for (var i = 0; i < segCount; i++, p += 2) {
|
||||||
|
var idOffset = getUshort(data, p);
|
||||||
|
if (idOffset === 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
ranges[i].ids = [];
|
||||||
|
for (var j = 0, jj = ranges[i].end - ranges[i].start + 1; j < jj; j++) {
|
||||||
|
ranges[i].ids[j] = getUshort(data, p + idOffset);
|
||||||
|
idOffset += 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ranges;
|
||||||
|
} else if (format === 12) {
|
||||||
|
var length = getLong(data, start + offset + 4);
|
||||||
|
var groups = getLong(data, start + offset + 12);
|
||||||
|
var p = start + offset + 16;
|
||||||
|
var ranges = [];
|
||||||
|
for (var i = 0; i < groups; i++) {
|
||||||
|
ranges.push({
|
||||||
|
start: getLong(data, p),
|
||||||
|
end: getLong(data, p + 4),
|
||||||
|
idDelta: getLong(data, p + 8) - getLong(data, p)
|
||||||
|
});
|
||||||
|
p += 12;
|
||||||
|
}
|
||||||
|
return ranges;
|
||||||
|
}
|
||||||
|
error('not supported cmap: ' + format);
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseCff(data, start, end) {
|
||||||
|
var properties = {};
|
||||||
|
var parser = new CFFParser(
|
||||||
|
new Stream(data, start, end - start), properties);
|
||||||
|
var cff = parser.parse();
|
||||||
|
return {
|
||||||
|
glyphs: cff.charStrings.objects,
|
||||||
|
subrs: cff.topDict.privateDict && cff.topDict.privateDict.subrsIndex &&
|
||||||
|
cff.topDict.privateDict.subrsIndex.objects,
|
||||||
|
gsubrs: cff.globalSubrIndex && cff.globalSubrIndex.objects
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseGlyfTable(glyf, loca, isGlyphLocationsLong) {
|
||||||
|
var itemSize, itemDecode;
|
||||||
|
if (isGlyphLocationsLong) {
|
||||||
|
itemSize = 4;
|
||||||
|
itemDecode = function fontItemDecodeLong(data, offset) {
|
||||||
|
return (data[offset] << 24) | (data[offset + 1] << 16) |
|
||||||
|
(data[offset + 2] << 8) | data[offset + 3];
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
itemSize = 2;
|
||||||
|
itemDecode = function fontItemDecode(data, offset) {
|
||||||
|
return (data[offset] << 9) | (data[offset + 1] << 1);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
var glyphs = [];
|
||||||
|
var startOffset = itemDecode(loca, 0);
|
||||||
|
for (var j = itemSize; j < loca.length; j += itemSize) {
|
||||||
|
var endOffset = itemDecode(loca, j);
|
||||||
|
glyphs.push(glyf.subarray(startOffset, endOffset));
|
||||||
|
startOffset = endOffset;
|
||||||
|
}
|
||||||
|
return glyphs;
|
||||||
|
}
|
||||||
|
|
||||||
|
function lookupCmap(ranges, unicode) {
|
||||||
|
var code = unicode.charCodeAt(0);
|
||||||
|
var l = 0, r = ranges.length - 1;
|
||||||
|
while (l < r) {
|
||||||
|
var c = (l + r + 1) >> 1;
|
||||||
|
if (code < ranges[c].start) {
|
||||||
|
r = c - 1;
|
||||||
|
} else {
|
||||||
|
l = c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ranges[l].start <= code && code <= ranges[l].end) {
|
||||||
|
return (ranges[l].idDelta + (ranges[l].ids ?
|
||||||
|
ranges[l].ids[code - ranges[l].start] : code)) & 0xFFFF;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
function compileGlyf(code, js, font) {
|
||||||
|
function moveTo(x, y) {
|
||||||
|
js.push('c.moveTo(' + x + ',' + y + ');');
|
||||||
|
}
|
||||||
|
function lineTo(x, y) {
|
||||||
|
js.push('c.lineTo(' + x + ',' + y + ');');
|
||||||
|
}
|
||||||
|
function quadraticCurveTo(xa, ya, x, y) {
|
||||||
|
js.push('c.quadraticCurveTo(' + xa + ',' + ya + ',' +
|
||||||
|
x + ',' + y + ');');
|
||||||
|
}
|
||||||
|
|
||||||
|
var i = 0;
|
||||||
|
var numberOfContours = ((code[i] << 24) | (code[i + 1] << 16)) >> 16;
|
||||||
|
var xMin = ((code[i + 2] << 24) | (code[i + 3] << 16)) >> 16;
|
||||||
|
var yMin = ((code[i + 4] << 24) | (code[i + 5] << 16)) >> 16;
|
||||||
|
var xMax = ((code[i + 6] << 24) | (code[i + 7] << 16)) >> 16;
|
||||||
|
var yMax = ((code[i + 8] << 24) | (code[i + 9] << 16)) >> 16;
|
||||||
|
i += 10;
|
||||||
|
if (numberOfContours < 0) {
|
||||||
|
// composite glyph
|
||||||
|
var x = 0, y = 0;
|
||||||
|
do {
|
||||||
|
var flags = (code[i] << 8) | code[i + 1];
|
||||||
|
var glyphIndex = (code[i + 2] << 8) | code[i + 3];
|
||||||
|
i += 4;
|
||||||
|
var arg1, arg2;
|
||||||
|
if ((flags & 0x01)) {
|
||||||
|
arg1 = ((code[i] << 24) | (code[i + 1] << 16)) >> 16;
|
||||||
|
arg2 = ((code[i + 2] << 24) | (code[i + 3] << 16)) >> 16;
|
||||||
|
i += 4;
|
||||||
|
} else {
|
||||||
|
arg1 = code[i++]; arg2 = code[i++];
|
||||||
|
}
|
||||||
|
if ((flags & 0x02)) {
|
||||||
|
x = arg1;
|
||||||
|
y = arg2;
|
||||||
|
} else {
|
||||||
|
x = 0; y = 0; // TODO "they are points" ?
|
||||||
|
}
|
||||||
|
var scaleX = 1, scaleY = 1, scale01 = 0, scale10 = 0;
|
||||||
|
if ((flags & 0x08)) {
|
||||||
|
scaleX =
|
||||||
|
scaleY = ((code[i] << 24) | (code[i + 1] << 16)) / 1073741824;
|
||||||
|
i += 2;
|
||||||
|
} else if ((flags & 0x40)) {
|
||||||
|
scaleX = ((code[i] << 24) | (code[i + 1] << 16)) / 1073741824;
|
||||||
|
scaleY = ((code[i + 2] << 24) | (code[i + 3] << 16)) / 1073741824;
|
||||||
|
i += 4;
|
||||||
|
} else if ((flags & 0x80)) {
|
||||||
|
scaleX = ((code[i] << 24) | (code[i + 1] << 16)) / 1073741824;
|
||||||
|
scale01 = ((code[i + 2] << 24) | (code[i + 3] << 16)) / 1073741824;
|
||||||
|
scale10 = ((code[i + 4] << 24) | (code[i + 5] << 16)) / 1073741824;
|
||||||
|
scaleY = ((code[i + 6] << 24) | (code[i + 7] << 16)) / 1073741824;
|
||||||
|
i += 8;
|
||||||
|
}
|
||||||
|
var subglyph = font.glyphs[glyphIndex];
|
||||||
|
if (subglyph) {
|
||||||
|
js.push('c.save();');
|
||||||
|
js.push('c.transform(' + scaleX + ',' + scale01 + ',' +
|
||||||
|
scale10 + ',' + scaleY + ',' + x + ',' + y + ');');
|
||||||
|
compileGlyf(subglyph, js, font);
|
||||||
|
js.push('c.restore();');
|
||||||
|
}
|
||||||
|
} while ((flags & 0x20));
|
||||||
|
} else {
|
||||||
|
// simple glyph
|
||||||
|
var endPtsOfContours = [];
|
||||||
|
for (var j = 0; j < numberOfContours; j++) {
|
||||||
|
endPtsOfContours.push((code[i] << 8) | code[i + 1]);
|
||||||
|
i += 2;
|
||||||
|
}
|
||||||
|
var instructionLength = (code[i] << 8) | code[i + 1];
|
||||||
|
i += 2 + instructionLength; // skipping the instructions
|
||||||
|
var numberOfPoints = endPtsOfContours[endPtsOfContours.length - 1] + 1;
|
||||||
|
var points = [];
|
||||||
|
while (points.length < numberOfPoints) {
|
||||||
|
var flags = code[i++], repeat = 1;
|
||||||
|
if ((flags & 0x08)) {
|
||||||
|
repeat += code[i++];
|
||||||
|
}
|
||||||
|
while (repeat-- > 0) {
|
||||||
|
points.push({flags: flags});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var x = 0, y = 0;
|
||||||
|
for (var j = 0; j < numberOfPoints; j++) {
|
||||||
|
switch (points[j].flags & 0x12) {
|
||||||
|
case 0x00:
|
||||||
|
x += ((code[i] << 24) | (code[i + 1] << 16)) >> 16;
|
||||||
|
i += 2;
|
||||||
|
break;
|
||||||
|
case 0x02:
|
||||||
|
x -= code[i++];
|
||||||
|
break;
|
||||||
|
case 0x12:
|
||||||
|
x += code[i++];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
points[j].x = x;
|
||||||
|
}
|
||||||
|
for (var j = 0; j < numberOfPoints; j++) {
|
||||||
|
switch (points[j].flags & 0x24) {
|
||||||
|
case 0x00:
|
||||||
|
y += ((code[i] << 24) | (code[i + 1] << 16)) >> 16;
|
||||||
|
i += 2;
|
||||||
|
break;
|
||||||
|
case 0x04:
|
||||||
|
y -= code[i++];
|
||||||
|
break;
|
||||||
|
case 0x24:
|
||||||
|
y += code[i++];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
points[j].y = y;
|
||||||
|
}
|
||||||
|
|
||||||
|
var startPoint = 0;
|
||||||
|
for (var i = 0; i < numberOfContours; i++) {
|
||||||
|
var endPoint = endPtsOfContours[i];
|
||||||
|
// contours might have implicit points, which is located in the middle
|
||||||
|
// between two neighboring off-curve points
|
||||||
|
var contour = points.slice(startPoint, endPoint + 1);
|
||||||
|
if ((contour[0].flags & 1)) {
|
||||||
|
contour.push(contour[0]); // using start point at the contour end
|
||||||
|
} else if ((contour[contour.length - 1].flags & 1)) {
|
||||||
|
// first is off-curve point, trying to use one from the end
|
||||||
|
contour.unshift(contour[contour.length - 1]);
|
||||||
|
} else {
|
||||||
|
// start and end are off-curve points, creating implicit one
|
||||||
|
var p = {
|
||||||
|
flags: 1,
|
||||||
|
x: (contour[0].x + contour[contour.length - 1].x) / 2,
|
||||||
|
y: (contour[0].y + contour[contour.length - 1].y) / 2
|
||||||
|
};
|
||||||
|
contour.unshift(p);
|
||||||
|
contour.push(p);
|
||||||
|
}
|
||||||
|
moveTo(contour[0].x, contour[0].y);
|
||||||
|
for (var j = 1, jj = contour.length; j < jj; j++) {
|
||||||
|
if ((contour[j].flags & 1)) {
|
||||||
|
lineTo(contour[j].x, contour[j].y);
|
||||||
|
} else if ((contour[j + 1].flags & 1)){
|
||||||
|
quadraticCurveTo(contour[j].x, contour[j].y,
|
||||||
|
contour[j + 1].x, contour[j + 1].y);
|
||||||
|
j++;
|
||||||
|
} else {
|
||||||
|
quadraticCurveTo(contour[j].x, contour[j].y,
|
||||||
|
(contour[j].x + contour[j + 1].x) / 2,
|
||||||
|
(contour[j].y + contour[j + 1].y) / 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
startPoint = endPoint + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function compileCharString(code, js, font) {
|
||||||
|
var stack = [];
|
||||||
|
var x = 0, y = 0;
|
||||||
|
var stems = 0;
|
||||||
|
|
||||||
|
function moveTo(x, y) {
|
||||||
|
js.push('c.moveTo(' + x + ',' + y + ');');
|
||||||
|
}
|
||||||
|
function lineTo(x, y) {
|
||||||
|
js.push('c.lineTo(' + x + ',' + y + ');');
|
||||||
|
}
|
||||||
|
function bezierCurveTo(x1, y1, x2, y2, x, y) {
|
||||||
|
js.push('c.bezierCurveTo(' + x1 + ',' + y1 + ',' + x2 + ',' + y2 + ',' +
|
||||||
|
x + ',' + y + ');');
|
||||||
|
}
|
||||||
|
|
||||||
|
function parse(code) {
|
||||||
|
var i = 0;
|
||||||
|
while (i < code.length) {
|
||||||
|
var stackClean = false;
|
||||||
|
var v = code[i++];
|
||||||
|
switch (v) {
|
||||||
|
case 1: // hstem
|
||||||
|
stems += stack.length >> 1;
|
||||||
|
stackClean = true;
|
||||||
|
break;
|
||||||
|
case 3: // vstem
|
||||||
|
stems += stack.length >> 1;
|
||||||
|
stackClean = true;
|
||||||
|
break;
|
||||||
|
case 4: // vmoveto
|
||||||
|
y += stack.pop();
|
||||||
|
moveTo(x, y);
|
||||||
|
stackClean = true;
|
||||||
|
break;
|
||||||
|
case 5: // rlineto
|
||||||
|
while (stack.length > 0) {
|
||||||
|
x += stack.shift();
|
||||||
|
y += stack.shift();
|
||||||
|
lineTo(x, y);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 6: // hlineto
|
||||||
|
while (stack.length > 0) {
|
||||||
|
x += stack.shift();
|
||||||
|
lineTo(x, y);
|
||||||
|
if (stack.length === 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
y += stack.shift();
|
||||||
|
lineTo(x, y);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 7: // vlineto
|
||||||
|
while (stack.length > 0) {
|
||||||
|
y += stack.shift();
|
||||||
|
lineTo(x, y);
|
||||||
|
if (stack.length === 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
x += stack.shift();
|
||||||
|
lineTo(x, y);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 8: // rrcurveto
|
||||||
|
while (stack.length > 0) {
|
||||||
|
var xa = x + stack.shift(), ya = y + stack.shift();
|
||||||
|
var xb = xa + stack.shift(), yb = ya + stack.shift();
|
||||||
|
x = xb + stack.shift(); y = yb + stack.shift();
|
||||||
|
bezierCurveTo(xa, ya, xb, yb, x, y);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 10: // callsubr
|
||||||
|
var n = stack.pop() + font.subrsBias;
|
||||||
|
var subrCode = font.subrs[n];
|
||||||
|
if (subrCode) {
|
||||||
|
parse(subrCode);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 11: // return
|
||||||
|
return;
|
||||||
|
case 12:
|
||||||
|
v = code[i++];
|
||||||
|
switch (v) {
|
||||||
|
case 34: // flex
|
||||||
|
var xa = x + stack.shift();
|
||||||
|
var xb = xa + stack.shift(), y1 = y + stack.shift();
|
||||||
|
x = xb + stack.shift();
|
||||||
|
bezierCurveTo(xa, y, xb, y1, x, y1);
|
||||||
|
var xa = x + stack.shift();
|
||||||
|
var xb = xa + stack.shift();
|
||||||
|
x = xb + stack.shift();
|
||||||
|
bezierCurveTo(xa, y1, xb, y, x, y);
|
||||||
|
break;
|
||||||
|
case 35: // flex
|
||||||
|
var xa = x + stack.shift(), ya = y + stack.shift();
|
||||||
|
var xb = xa + stack.shift(), yb = ya + stack.shift();
|
||||||
|
x = xb + stack.shift(); y = yb + stack.shift();
|
||||||
|
bezierCurveTo(xa, ya, xb, yb, x, y);
|
||||||
|
var xa = x + stack.shift(), ya = y + stack.shift();
|
||||||
|
var xb = xa + stack.shift(), yb = ya + stack.shift();
|
||||||
|
x = xb + stack.shift(); y = yb + stack.shift();
|
||||||
|
bezierCurveTo(xa, ya, xb, yb, x, y);
|
||||||
|
stack.pop(); // fd
|
||||||
|
break;
|
||||||
|
case 36: // hflex1
|
||||||
|
var xa = x + stack.shift(), y1 = y + stack.shift();
|
||||||
|
var xb = xa + stack.shift(), y2 = y1 + stack.shift();
|
||||||
|
x = xb + stack.shift();
|
||||||
|
bezierCurveTo(xa, y1, xb, y2, x, y2);
|
||||||
|
var xa = x + stack.shift();
|
||||||
|
var xb = xa + stack.shift(), y3 = y2 + stack.shift();
|
||||||
|
x = xb + stack.shift();
|
||||||
|
bezierCurveTo(xa, y2, xb, y3, x, y);
|
||||||
|
break;
|
||||||
|
case 37: // flex1
|
||||||
|
var x0 = x, y0 = y;
|
||||||
|
var xa = x + stack.shift(), ya = y + stack.shift();
|
||||||
|
var xb = xa + stack.shift(), yb = ya + stack.shift();
|
||||||
|
x = xb + stack.shift(); y = yb + stack.shift();
|
||||||
|
bezierCurveTo(xa, ya, xb, yb, x, y);
|
||||||
|
var xa = x + stack.shift(), ya = y + stack.shift();
|
||||||
|
var xb = xa + stack.shift(), yb = ya + stack.shift();
|
||||||
|
x = xb; y = yb;
|
||||||
|
if (Math.abs(x - x0) > Math.abs(y - y0))
|
||||||
|
x += stack.shift();
|
||||||
|
else
|
||||||
|
y += stack.shift();
|
||||||
|
bezierCurveTo(xa, ya, xb, yb, x, y);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
error('unknown operator: 12 ' + v);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 14: // endchar
|
||||||
|
if (stack.length >= 4) {
|
||||||
|
var achar = stack.pop();
|
||||||
|
var bchar = stack.pop();
|
||||||
|
y = stack.pop();
|
||||||
|
x = stack.pop();
|
||||||
|
js.push('c.save();');
|
||||||
|
js.push('c.translate('+ x + ',' + y + ');');
|
||||||
|
var gid = lookupCmap(font.cmap, String.fromCharCode(
|
||||||
|
font.glyphNameMap[Encodings.StandardEncoding[achar]]));
|
||||||
|
compileCharString(font.glyphs[gid], js, font);
|
||||||
|
js.push('c.restore();');
|
||||||
|
|
||||||
|
gid = lookupCmap(font.cmap, String.fromCharCode(
|
||||||
|
font.glyphNameMap[Encodings.StandardEncoding[bchar]]));
|
||||||
|
compileCharString(font.glyphs[gid], js, font);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
case 18: // hstemhm
|
||||||
|
stems += stack.length >> 1;
|
||||||
|
stackClean = true;
|
||||||
|
break;
|
||||||
|
case 19: // hintmask
|
||||||
|
stems += stack.length >> 1;
|
||||||
|
i += (stems + 7) >> 3;
|
||||||
|
stackClean = true;
|
||||||
|
break;
|
||||||
|
case 20: // cntrmask
|
||||||
|
stems += stack.length >> 1;
|
||||||
|
i += (stems + 7) >> 3;
|
||||||
|
stackClean = true;
|
||||||
|
break;
|
||||||
|
case 21: // rmoveto
|
||||||
|
y += stack.pop();
|
||||||
|
x += stack.pop();
|
||||||
|
moveTo(x, y);
|
||||||
|
stackClean = true;
|
||||||
|
break;
|
||||||
|
case 22: // hmoveto
|
||||||
|
x += stack.pop();
|
||||||
|
moveTo(x, y);
|
||||||
|
stackClean = true;
|
||||||
|
break;
|
||||||
|
case 23: // vstemhm
|
||||||
|
stems += stack.length >> 1;
|
||||||
|
stackClean = true;
|
||||||
|
break;
|
||||||
|
case 24: // rcurveline
|
||||||
|
while (stack.length > 2) {
|
||||||
|
var xa = x + stack.shift(), ya = y + stack.shift();
|
||||||
|
var xb = xa + stack.shift(), yb = ya + stack.shift();
|
||||||
|
x = xb + stack.shift(); y = yb + stack.shift();
|
||||||
|
bezierCurveTo(xa, ya, xb, yb, x, y);
|
||||||
|
}
|
||||||
|
x += stack.shift();
|
||||||
|
y += stack.shift();
|
||||||
|
lineTo(x, y);
|
||||||
|
break;
|
||||||
|
case 25: // rlinecurve
|
||||||
|
while (stack.length > 6) {
|
||||||
|
x += stack.shift();
|
||||||
|
y += stack.shift();
|
||||||
|
lineTo(x, y);
|
||||||
|
}
|
||||||
|
var xa = x + stack.shift(), ya = y + stack.shift();
|
||||||
|
var xb = xa + stack.shift(), yb = ya + stack.shift();
|
||||||
|
x = xb + stack.shift(); y = yb + stack.shift();
|
||||||
|
bezierCurveTo(xa, ya, xb, yb, x, y);
|
||||||
|
break;
|
||||||
|
case 26: // vvcurveto
|
||||||
|
if (stack.length % 2) {
|
||||||
|
x += stack.shift();
|
||||||
|
}
|
||||||
|
while (stack.length > 0) {
|
||||||
|
var xa = x, ya = y + stack.shift();
|
||||||
|
var xb = xa + stack.shift(), yb = ya + stack.shift();
|
||||||
|
x = xb; y = yb + stack.shift();
|
||||||
|
bezierCurveTo(xa, ya, xb, yb, x, y);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 27: // hhcurveto
|
||||||
|
if (stack.length % 2) {
|
||||||
|
y += stack.shift();
|
||||||
|
}
|
||||||
|
while (stack.length > 0) {
|
||||||
|
var xa = x + stack.shift(), ya = y;
|
||||||
|
var xb = xa + stack.shift(), yb = ya + stack.shift();
|
||||||
|
x = xb + stack.shift(); y = yb;
|
||||||
|
bezierCurveTo(xa, ya, xb, yb, x, y);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 28:
|
||||||
|
stack.push(((code[i] << 24) | (code[i + 1] << 16)) >> 16);
|
||||||
|
i += 2;
|
||||||
|
break;
|
||||||
|
case 29: // callgsubr
|
||||||
|
var n = stack.pop() + font.gsubrsBias;
|
||||||
|
var subrCode = font.gsubrs[n];
|
||||||
|
if (subrCode) {
|
||||||
|
parse(subrCode);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 30: // vhcurveto
|
||||||
|
while (stack.length > 0) {
|
||||||
|
var xa = x, ya = y + stack.shift();
|
||||||
|
var xb = xa + stack.shift(), yb = ya + stack.shift();
|
||||||
|
x = xb + stack.shift();
|
||||||
|
y = yb + (stack.length === 1 ? stack.shift() : 0);
|
||||||
|
bezierCurveTo(xa, ya, xb, yb, x, y);
|
||||||
|
if (stack.length === 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
var xa = x + stack.shift(), ya = y;
|
||||||
|
var xb = xa + stack.shift(), yb = ya + stack.shift();
|
||||||
|
y = yb + stack.shift();
|
||||||
|
x = xb + (stack.length === 1 ? stack.shift() : 0);
|
||||||
|
bezierCurveTo(xa, ya, xb, yb, x, y);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 31: // hvcurveto
|
||||||
|
while (stack.length > 0) {
|
||||||
|
var xa = x + stack.shift(), ya = y;
|
||||||
|
var xb = xa + stack.shift(), yb = ya + stack.shift();
|
||||||
|
y = yb + stack.shift();
|
||||||
|
x = xb + (stack.length === 1 ? stack.shift() : 0);
|
||||||
|
bezierCurveTo(xa, ya, xb, yb, x, y);
|
||||||
|
if (stack.length === 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
var xa = x, ya = y + stack.shift();
|
||||||
|
var xb = xa + stack.shift(), yb = ya + stack.shift();
|
||||||
|
x = xb + stack.shift();
|
||||||
|
y = yb + (stack.length === 1 ? stack.shift() : 0);
|
||||||
|
bezierCurveTo(xa, ya, xb, yb, x, y);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if (v < 32)
|
||||||
|
error('unknown operator: ' + v);
|
||||||
|
if (v < 247)
|
||||||
|
stack.push(v - 139);
|
||||||
|
else if (v < 251)
|
||||||
|
stack.push((v - 247) * 256 + code[i++] + 108);
|
||||||
|
else if (v < 255)
|
||||||
|
stack.push(-(v - 251) * 256 - code[i++] - 108);
|
||||||
|
else {
|
||||||
|
stack.push(((code[i] << 24) | (code[i + 1] << 16) |
|
||||||
|
(code[i + 2] << 8) | code[i + 3]) / 65536);
|
||||||
|
i += 4;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (stackClean) {
|
||||||
|
stack.length = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
parse(code);
|
||||||
|
}
|
||||||
|
|
||||||
|
function TrueTypeCompiled(glyphs, cmap, fontMatrix) {
|
||||||
|
this.glyphs = glyphs;
|
||||||
|
this.cmap = cmap;
|
||||||
|
this.fontMatrix = fontMatrix || [0.000488, 0, 0, 0.000488, 0, 0];
|
||||||
|
|
||||||
|
this.compiledGlyphs = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
var noop = function () {};
|
||||||
|
|
||||||
|
TrueTypeCompiled.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;
|
||||||
|
compileGlyf(code, js, this);
|
||||||
|
|
||||||
|
js.push('c.restore();');
|
||||||
|
|
||||||
|
/*jshint -W054 */
|
||||||
|
return new Function('c', 'size', js.join('\n'));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
function Type2Compiled(cffInfo, cmap, fontMatrix, glyphNameMap) {
|
||||||
|
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 :
|
||||||
|
this.gsubrs.length < 33900 ? 1131 : 32768;
|
||||||
|
this.subrsBias = this.subrs.length < 1240 ? 107 :
|
||||||
|
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;
|
||||||
|
compileCharString(code, js, this);
|
||||||
|
|
||||||
|
js.push('c.restore();');
|
||||||
|
|
||||||
|
/*jshint -W054 */
|
||||||
|
return new Function('c', 'size', js.join('\n'));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
create: function FontRendererFactory_create(font) {
|
||||||
|
var data = new Uint8Array(font.data);
|
||||||
|
var cmap, glyf, loca, cff, indexToLocFormat, unitsPerEm;
|
||||||
|
var numTables = getUshort(data, 4);
|
||||||
|
for (var i = 0, p = 12; i < numTables; i++, p += 16) {
|
||||||
|
var tag = String.fromCharCode.apply(null, data.subarray(p, p + 4));
|
||||||
|
var offset = getLong(data, p + 8);
|
||||||
|
var length = getLong(data, p + 12);
|
||||||
|
switch (tag) {
|
||||||
|
case 'cmap':
|
||||||
|
cmap = parseCmap(data, offset, offset + length);
|
||||||
|
break;
|
||||||
|
case 'glyf':
|
||||||
|
glyf = data.subarray(offset, offset + length);
|
||||||
|
break;
|
||||||
|
case 'loca':
|
||||||
|
loca = data.subarray(offset, offset + length);
|
||||||
|
break;
|
||||||
|
case 'head':
|
||||||
|
unitsPerEm = getUshort(data, offset + 18);
|
||||||
|
indexToLocFormat = getUshort(data, offset + 50);
|
||||||
|
break;
|
||||||
|
case 'CFF ':
|
||||||
|
cff = parseCff(data, offset, offset + length);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (glyf) {
|
||||||
|
var fontMatrix = !unitsPerEm ? font.fontMatrix :
|
||||||
|
[1 / unitsPerEm, 0, 0, 1 / unitsPerEm, 0, 0];
|
||||||
|
return new TrueTypeCompiled(
|
||||||
|
parseGlyfTable(glyf, loca, indexToLocFormat), cmap, fontMatrix);
|
||||||
|
} else {
|
||||||
|
return new Type2Compiled(cff, cmap, font.fontMatrix, font.glyphNameMap);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
})();
|
||||||
|
|
15
src/fonts.js
15
src/fonts.js
@ -17,7 +17,8 @@
|
|||||||
/* globals assert, bytesToString, CIDToUnicodeMaps, error, ExpertCharset,
|
/* globals assert, bytesToString, CIDToUnicodeMaps, error, ExpertCharset,
|
||||||
ExpertSubsetCharset, FileReaderSync, globalScope, GlyphsUnicode,
|
ExpertSubsetCharset, FileReaderSync, globalScope, GlyphsUnicode,
|
||||||
info, isArray, isNum, ISOAdobeCharset, isWorker, PDFJS, Stream,
|
info, isArray, isNum, ISOAdobeCharset, isWorker, PDFJS, Stream,
|
||||||
stringToBytes, TextDecoder, TODO, warn, Lexer, Util */
|
stringToBytes, TextDecoder, TODO, warn, Lexer, Util, shadow,
|
||||||
|
FontRendererFactory */
|
||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
@ -40,6 +41,8 @@ var SEAC_ANALYSIS_ENABLED = false;
|
|||||||
|
|
||||||
var FONT_IDENTITY_MATRIX = [0.001, 0, 0, 0.001, 0, 0];
|
var FONT_IDENTITY_MATRIX = [0.001, 0, 0, 0.001, 0, 0];
|
||||||
|
|
||||||
|
PDFJS.disableFontFace = false;
|
||||||
|
|
||||||
var FontFlags = {
|
var FontFlags = {
|
||||||
FixedPitch: 1,
|
FixedPitch: 1,
|
||||||
Serif: 2,
|
Serif: 2,
|
||||||
@ -3019,6 +3022,11 @@ var Font = (function FontClosure() {
|
|||||||
mimetype: null,
|
mimetype: null,
|
||||||
encoding: null,
|
encoding: null,
|
||||||
|
|
||||||
|
get renderer() {
|
||||||
|
var renderer = FontRendererFactory.create(this);
|
||||||
|
return shadow(this, 'renderer', renderer);
|
||||||
|
},
|
||||||
|
|
||||||
exportData: function Font_exportData() {
|
exportData: function Font_exportData() {
|
||||||
var data = {};
|
var data = {};
|
||||||
for (var i in this) {
|
for (var i in this) {
|
||||||
@ -4565,6 +4573,11 @@ var Font = (function FontClosure() {
|
|||||||
if (!this.data)
|
if (!this.data)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
|
if (PDFJS.disableFontFace) {
|
||||||
|
this.disableFontFace = true;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
var data = bytesToString(this.data);
|
var data = bytesToString(this.data);
|
||||||
var fontName = this.loadedName;
|
var fontName = this.loadedName;
|
||||||
|
|
||||||
|
@ -35,6 +35,7 @@ limitations under the License.
|
|||||||
<script type="text/javascript" src="/src/crypto.js"></script>
|
<script type="text/javascript" src="/src/crypto.js"></script>
|
||||||
<script type="text/javascript" src="/src/evaluator.js"></script>
|
<script type="text/javascript" src="/src/evaluator.js"></script>
|
||||||
<script type="text/javascript" src="/src/fonts.js"></script>
|
<script type="text/javascript" src="/src/fonts.js"></script>
|
||||||
|
<script type="text/javascript" src="/src/font_renderer.js"></script>
|
||||||
<script type="text/javascript" src="/src/glyphlist.js"></script>
|
<script type="text/javascript" src="/src/glyphlist.js"></script>
|
||||||
<script type="text/javascript" src="/src/image.js"></script>
|
<script type="text/javascript" src="/src/image.js"></script>
|
||||||
<script type="text/javascript" src="/src/metrics.js"></script>
|
<script type="text/javascript" src="/src/metrics.js"></script>
|
||||||
|
@ -55,6 +55,7 @@ limitations under the License.
|
|||||||
<script type="text/javascript" src="../src/crypto.js"></script>
|
<script type="text/javascript" src="../src/crypto.js"></script>
|
||||||
<script type="text/javascript" src="../src/evaluator.js"></script>
|
<script type="text/javascript" src="../src/evaluator.js"></script>
|
||||||
<script type="text/javascript" src="../src/fonts.js"></script>
|
<script type="text/javascript" src="../src/fonts.js"></script>
|
||||||
|
<script type="text/javascript" src="../src/font_renderer.js"></script>
|
||||||
<script type="text/javascript" src="../src/glyphlist.js"></script>
|
<script type="text/javascript" src="../src/glyphlist.js"></script>
|
||||||
<script type="text/javascript" src="../src/image.js"></script>
|
<script type="text/javascript" src="../src/image.js"></script>
|
||||||
<script type="text/javascript" src="../src/metrics.js"></script>
|
<script type="text/javascript" src="../src/metrics.js"></script>
|
||||||
|
@ -2330,7 +2330,7 @@ var PageView = function pageView(container, id, scale,
|
|||||||
|
|
||||||
//#if (FIREFOX || MOZCENTRAL)
|
//#if (FIREFOX || MOZCENTRAL)
|
||||||
// if (checkIfDocumentFontsUsed && PDFView.pdfDocument.embeddedFontsUsed &&
|
// if (checkIfDocumentFontsUsed && PDFView.pdfDocument.embeddedFontsUsed &&
|
||||||
// !PDFView.supportsDocumentFonts) {
|
// PDFJS.disableFontFace) {
|
||||||
// console.error(mozL10n.get('web_fonts_disabled', null,
|
// console.error(mozL10n.get('web_fonts_disabled', null,
|
||||||
// 'Web fonts are disabled: unable to use embedded PDF fonts.'));
|
// 'Web fonts are disabled: unable to use embedded PDF fonts.'));
|
||||||
// PDFView.fallback();
|
// PDFView.fallback();
|
||||||
@ -3107,11 +3107,20 @@ document.addEventListener('DOMContentLoaded', function webViewerLoad(evt) {
|
|||||||
PDFJS.disableAutoFetch = (hashParams['disableAutoFetch'] === 'true');
|
PDFJS.disableAutoFetch = (hashParams['disableAutoFetch'] === 'true');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ('disableFontFace' in hashParams) {
|
||||||
|
PDFJS.disableFontFace = (hashParams['disableFontFace'] === 'true');
|
||||||
|
}
|
||||||
|
|
||||||
//#if !(FIREFOX || MOZCENTRAL)
|
//#if !(FIREFOX || MOZCENTRAL)
|
||||||
var locale = navigator.language;
|
var locale = navigator.language;
|
||||||
if ('locale' in hashParams)
|
if ('locale' in hashParams)
|
||||||
locale = hashParams['locale'];
|
locale = hashParams['locale'];
|
||||||
mozL10n.setLanguage(locale);
|
mozL10n.setLanguage(locale);
|
||||||
|
//#endif
|
||||||
|
//#if (FIREFOX || MOZCENTRAL)
|
||||||
|
//if (!PDFView.supportsDocumentFonts) {
|
||||||
|
// PDFJS.disableFontFace = true;
|
||||||
|
//}
|
||||||
//#endif
|
//#endif
|
||||||
|
|
||||||
if ('textLayer' in hashParams) {
|
if ('textLayer' in hashParams) {
|
||||||
|
Loading…
Reference in New Issue
Block a user