Merge branch 'master' of git://github.com/mozilla/pdf.js.git into textsearch-1
This commit is contained in:
commit
b8672d7efb
@ -257,9 +257,6 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
|
|||||||
this.ctx.scale(cw / mediaBox.width, ch / mediaBox.height);
|
this.ctx.scale(cw / mediaBox.width, ch / mediaBox.height);
|
||||||
this.textDivs = [];
|
this.textDivs = [];
|
||||||
this.textLayerQueue = [];
|
this.textLayerQueue = [];
|
||||||
// Prevent textLayerQueue from being rendered while rendering a new page
|
|
||||||
if (this.textLayerTimer)
|
|
||||||
clearTimeout(this.textLayerTimer);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
executeIRQueue: function canvasGraphicsExecuteIRQueue(codeIR,
|
executeIRQueue: function canvasGraphicsExecuteIRQueue(codeIR,
|
||||||
@ -328,31 +325,22 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
var self = this;
|
var self = this;
|
||||||
var renderTextLayer = function canvasRenderTextLayer() {
|
var textDivs = this.textDivs;
|
||||||
var textDivs = self.textDivs;
|
this.textLayerTimer = setInterval(function renderTextLayer() {
|
||||||
for (var i = 0, length = textDivs.length; i < length; ++i) {
|
if (textDivs.length === 0) {
|
||||||
if (textDivs[i].dataset.textLength > 1) { // avoid div by zero
|
clearInterval(self.textLayerTimer);
|
||||||
textLayer.appendChild(textDivs[i]);
|
return;
|
||||||
// Adjust div width (via letterSpacing) to match canvas text
|
|
||||||
// Due to the .offsetWidth calls, this is slow
|
|
||||||
textDivs[i].style.letterSpacing =
|
|
||||||
((textDivs[i].dataset.canvasWidth - textDivs[i].offsetWidth) /
|
|
||||||
(textDivs[i].dataset.textLength - 1)) + 'px';
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
var textDiv = textDivs.shift();
|
||||||
var textLayerQueue = this.textLayerQueue;
|
if (textDiv.dataset.textLength > 1) { // avoid div by zero
|
||||||
textLayerQueue.push(renderTextLayer);
|
textLayer.appendChild(textDiv);
|
||||||
|
// Adjust div width (via letterSpacing) to match canvas text
|
||||||
// Lazy textLayer rendering (to prevent UI hangs)
|
// Due to the .offsetWidth calls, this is slow
|
||||||
// Only render queue if activity has stopped, where "no activity" ==
|
textDiv.style.letterSpacing =
|
||||||
// "no beginDrawing() calls in the last N ms"
|
((textDiv.dataset.canvasWidth - textDiv.offsetWidth) /
|
||||||
this.textLayerTimer = setTimeout(function renderTextLayerQueue() {
|
(textDiv.dataset.textLength - 1)) + 'px';
|
||||||
// Render most recent (==most relevant) layers first
|
|
||||||
for (var i = textLayerQueue.length - 1; i >= 0; i--) {
|
|
||||||
textLayerQueue.pop().call();
|
|
||||||
}
|
}
|
||||||
}, 500);
|
}, 0);
|
||||||
},
|
},
|
||||||
|
|
||||||
// Graphics state
|
// Graphics state
|
||||||
@ -1106,9 +1094,9 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
|
|||||||
|
|
||||||
paintImageXObject: function canvasGraphicsPaintImageXObject(objId) {
|
paintImageXObject: function canvasGraphicsPaintImageXObject(objId) {
|
||||||
var imgData = this.objs.get(objId);
|
var imgData = this.objs.get(objId);
|
||||||
if (!imgData) {
|
if (!imgData)
|
||||||
error('Dependent image isn\'t ready yet');
|
error('Dependent image isn\'t ready yet');
|
||||||
}
|
|
||||||
this.save();
|
this.save();
|
||||||
var ctx = this.ctx;
|
var ctx = this.ctx;
|
||||||
var w = imgData.width;
|
var w = imgData.width;
|
||||||
|
@ -154,6 +154,29 @@ var ColorSpace = (function ColorSpaceClosure() {
|
|||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
|
/**
|
||||||
|
* Checks if a decode map matches the default decode map for a color space.
|
||||||
|
* This handles the general decode maps where there are two values per
|
||||||
|
* component. e.g. [0, 1, 0, 1, 0, 1] for a RGB color.
|
||||||
|
* This does not handle Lab, Indexed, or Pattern decode maps since they are
|
||||||
|
* slightly different.
|
||||||
|
* @param {Array} decode Decode map (usually from an image).
|
||||||
|
* @param {Number} n Number of components the color space has.
|
||||||
|
*/
|
||||||
|
ColorSpace.isDefaultDecode = function colorSpaceIsDefaultDecode(decode, n) {
|
||||||
|
if (!decode)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (n * 2 !== decode.length) {
|
||||||
|
warning('The decode map is not the correct length');
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
for (var i = 0, ii = decode.length; i < ii; i += 2) {
|
||||||
|
if (decode[i] != 0 || decode[i + 1] != 1)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
return ColorSpace;
|
return ColorSpace;
|
||||||
})();
|
})();
|
||||||
@ -200,6 +223,9 @@ var AlternateCS = (function AlternateCSClosure() {
|
|||||||
baseBuf[pos++] = 255 * tinted[j];
|
baseBuf[pos++] = 255 * tinted[j];
|
||||||
}
|
}
|
||||||
return base.getRgbBuffer(baseBuf, 8);
|
return base.getRgbBuffer(baseBuf, 8);
|
||||||
|
},
|
||||||
|
isDefaultDecode: function altcs_isDefaultDecode(decodeMap) {
|
||||||
|
ColorSpace.isDefaultDecode(decodeMap, this.numComps);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -267,6 +293,10 @@ var IndexedCS = (function IndexedCSClosure() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return base.getRgbBuffer(baseBuf, 8);
|
return base.getRgbBuffer(baseBuf, 8);
|
||||||
|
},
|
||||||
|
isDefaultDecode: function indexcs_isDefaultDecode(decodeMap) {
|
||||||
|
// indexed color maps shouldn't be changed
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
return IndexedCS;
|
return IndexedCS;
|
||||||
@ -295,6 +325,9 @@ var DeviceGrayCS = (function DeviceGrayCSClosure() {
|
|||||||
rgbBuf[j++] = c;
|
rgbBuf[j++] = c;
|
||||||
}
|
}
|
||||||
return rgbBuf;
|
return rgbBuf;
|
||||||
|
},
|
||||||
|
isDefaultDecode: function graycs_isDefaultDecode(decodeMap) {
|
||||||
|
ColorSpace.isDefaultDecode(decodeMap, this.numComps);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
return DeviceGrayCS;
|
return DeviceGrayCS;
|
||||||
@ -319,6 +352,9 @@ var DeviceRgbCS = (function DeviceRgbCSClosure() {
|
|||||||
for (i = 0; i < length; ++i)
|
for (i = 0; i < length; ++i)
|
||||||
rgbBuf[i] = (scale * input[i]) | 0;
|
rgbBuf[i] = (scale * input[i]) | 0;
|
||||||
return rgbBuf;
|
return rgbBuf;
|
||||||
|
},
|
||||||
|
isDefaultDecode: function rgbcs_isDefaultDecode(decodeMap) {
|
||||||
|
ColorSpace.isDefaultDecode(decodeMap, this.numComps);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
return DeviceRgbCS;
|
return DeviceRgbCS;
|
||||||
@ -403,6 +439,9 @@ var DeviceCmykCS = (function DeviceCmykCSClosure() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return rgbBuf;
|
return rgbBuf;
|
||||||
|
},
|
||||||
|
isDefaultDecode: function cmykcs_isDefaultDecode(decodeMap) {
|
||||||
|
ColorSpace.isDefaultDecode(decodeMap, this.numComps);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -227,7 +227,7 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
|
|||||||
data: new Uint8Array(w * h * 4)
|
data: new Uint8Array(w * h * 4)
|
||||||
};
|
};
|
||||||
var pixels = imgData.data;
|
var pixels = imgData.data;
|
||||||
imageObj.fillRgbaBuffer(pixels, imageObj.decode);
|
imageObj.fillRgbaBuffer(pixels);
|
||||||
handler.send('obj', [objId, 'Image', imgData]);
|
handler.send('obj', [objId, 'Image', imgData]);
|
||||||
}, handler, xref, resources, image, inline);
|
}, handler, xref, resources, image, inline);
|
||||||
}
|
}
|
||||||
|
68
src/image.js
68
src/image.js
@ -24,6 +24,15 @@ var PDFImage = (function PDFImageClosure() {
|
|||||||
promise.resolve(image);
|
promise.resolve(image);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* Decode and clamp a value. The formula is different from the spec because we
|
||||||
|
* don't decode to float range [0,1], we decode it in the [0,max] range.
|
||||||
|
*/
|
||||||
|
function decodeAndClamp(value, addend, coefficient, max) {
|
||||||
|
value = addend + value * coefficient;
|
||||||
|
// Clamp the value to the range
|
||||||
|
return value < 0 ? 0 : value > max ? max : value;
|
||||||
|
}
|
||||||
function PDFImage(xref, res, image, inline, smask) {
|
function PDFImage(xref, res, image, inline, smask) {
|
||||||
this.image = image;
|
this.image = image;
|
||||||
if (image.getParams) {
|
if (image.getParams) {
|
||||||
@ -69,6 +78,21 @@ var PDFImage = (function PDFImageClosure() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.decode = dict.get('Decode', 'D');
|
this.decode = dict.get('Decode', 'D');
|
||||||
|
this.needsDecode = false;
|
||||||
|
if (this.decode && this.colorSpace &&
|
||||||
|
!this.colorSpace.isDefaultDecode(this.decode)) {
|
||||||
|
this.needsDecode = true;
|
||||||
|
// Do some preprocessing to avoid more math.
|
||||||
|
var max = (1 << bitsPerComponent) - 1;
|
||||||
|
this.decodeCoefficients = [];
|
||||||
|
this.decodeAddends = [];
|
||||||
|
for (var i = 0, j = 0; i < this.decode.length; i += 2, ++j) {
|
||||||
|
var dmin = this.decode[i];
|
||||||
|
var dmax = this.decode[i + 1];
|
||||||
|
this.decodeCoefficients[j] = dmax - dmin;
|
||||||
|
this.decodeAddends[j] = max * dmin;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var mask = xref.fetchIfRef(dict.get('Mask'));
|
var mask = xref.fetchIfRef(dict.get('Mask'));
|
||||||
|
|
||||||
@ -104,22 +128,43 @@ var PDFImage = (function PDFImageClosure() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
PDFImage.prototype = {
|
PDFImage.prototype = {
|
||||||
getComponents: function getComponents(buffer, decodeMap) {
|
getComponents: function getComponents(buffer) {
|
||||||
var bpc = this.bpc;
|
var bpc = this.bpc;
|
||||||
if (bpc == 8)
|
var needsDecode = this.needsDecode;
|
||||||
|
var decodeMap = this.decode;
|
||||||
|
|
||||||
|
// This image doesn't require any extra work.
|
||||||
|
if (bpc == 8 && !needsDecode)
|
||||||
return buffer;
|
return buffer;
|
||||||
|
|
||||||
|
var bufferLength = buffer.length;
|
||||||
var width = this.width;
|
var width = this.width;
|
||||||
var height = this.height;
|
var height = this.height;
|
||||||
var numComps = this.numComps;
|
var numComps = this.numComps;
|
||||||
|
|
||||||
var length = width * height;
|
var length = width * height * numComps;
|
||||||
var bufferPos = 0;
|
var bufferPos = 0;
|
||||||
var output = bpc <= 8 ? new Uint8Array(length) :
|
var output = bpc <= 8 ? new Uint8Array(length) :
|
||||||
bpc <= 16 ? new Uint16Array(length) : new Uint32Array(length);
|
bpc <= 16 ? new Uint16Array(length) : new Uint32Array(length);
|
||||||
var rowComps = width * numComps;
|
var rowComps = width * numComps;
|
||||||
|
var decodeAddends, decodeCoefficients;
|
||||||
|
if (needsDecode) {
|
||||||
|
decodeAddends = this.decodeAddends;
|
||||||
|
decodeCoefficients = this.decodeCoefficients;
|
||||||
|
}
|
||||||
|
var max = (1 << bpc) - 1;
|
||||||
|
|
||||||
if (bpc == 1) {
|
if (bpc == 8) {
|
||||||
|
// Optimization for reading 8 bpc images that have a decode.
|
||||||
|
for (var i = 0, ii = length; i < ii; ++i) {
|
||||||
|
var compIndex = i % numComps;
|
||||||
|
var value = buffer[i];
|
||||||
|
value = decodeAndClamp(value, decodeAddends[compIndex],
|
||||||
|
decodeCoefficients[compIndex], max);
|
||||||
|
output[i] = value;
|
||||||
|
}
|
||||||
|
} else if (bpc == 1) {
|
||||||
|
// Optimization for reading 1 bpc images.
|
||||||
var valueZero = 0, valueOne = 1;
|
var valueZero = 0, valueOne = 1;
|
||||||
if (decodeMap) {
|
if (decodeMap) {
|
||||||
valueZero = decodeMap[0] ? 1 : 0;
|
valueZero = decodeMap[0] ? 1 : 0;
|
||||||
@ -144,8 +189,7 @@ var PDFImage = (function PDFImageClosure() {
|
|||||||
output[i] = !(buf & mask) ? valueZero : valueOne;
|
output[i] = !(buf & mask) ? valueZero : valueOne;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (decodeMap != null)
|
// The general case that handles all other bpc values.
|
||||||
TODO('interpolate component values');
|
|
||||||
var bits = 0, buf = 0;
|
var bits = 0, buf = 0;
|
||||||
for (var i = 0, ii = length; i < ii; ++i) {
|
for (var i = 0, ii = length; i < ii; ++i) {
|
||||||
if (i % rowComps == 0) {
|
if (i % rowComps == 0) {
|
||||||
@ -159,7 +203,13 @@ var PDFImage = (function PDFImageClosure() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var remainingBits = bits - bpc;
|
var remainingBits = bits - bpc;
|
||||||
output[i] = buf >> remainingBits;
|
var value = buf >> remainingBits;
|
||||||
|
if (needsDecode) {
|
||||||
|
var compIndex = i % numComps;
|
||||||
|
value = decodeAndClamp(value, decodeAddends[compIndex],
|
||||||
|
decodeCoefficients[compIndex], max);
|
||||||
|
}
|
||||||
|
output[i] = value;
|
||||||
buf = buf & ((1 << remainingBits) - 1);
|
buf = buf & ((1 << remainingBits) - 1);
|
||||||
bits = remainingBits;
|
bits = remainingBits;
|
||||||
}
|
}
|
||||||
@ -210,7 +260,7 @@ var PDFImage = (function PDFImageClosure() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
fillRgbaBuffer: function fillRgbaBuffer(buffer, decodeMap) {
|
fillRgbaBuffer: function fillRgbaBuffer(buffer) {
|
||||||
var numComps = this.numComps;
|
var numComps = this.numComps;
|
||||||
var width = this.width;
|
var width = this.width;
|
||||||
var height = this.height;
|
var height = this.height;
|
||||||
@ -221,7 +271,7 @@ var PDFImage = (function PDFImageClosure() {
|
|||||||
var imgArray = this.getImageBytes(height * rowBytes);
|
var imgArray = this.getImageBytes(height * rowBytes);
|
||||||
|
|
||||||
var comps = this.colorSpace.getRgbBuffer(
|
var comps = this.colorSpace.getRgbBuffer(
|
||||||
this.getComponents(imgArray, decodeMap), bpc);
|
this.getComponents(imgArray), bpc);
|
||||||
var compsPos = 0;
|
var compsPos = 0;
|
||||||
var opacity = this.getOpacity();
|
var opacity = this.getOpacity();
|
||||||
var opacityPos = 0;
|
var opacityPos = 0;
|
||||||
|
11
src/obj.js
11
src/obj.js
@ -22,6 +22,17 @@ var Cmd = (function CmdClosure() {
|
|||||||
Cmd.prototype = {
|
Cmd.prototype = {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
var cmdCache = {};
|
||||||
|
|
||||||
|
Cmd.get = function cmdGet(cmd) {
|
||||||
|
var cmdValue = cmdCache[cmd];
|
||||||
|
if (cmdValue)
|
||||||
|
return cmdValue;
|
||||||
|
|
||||||
|
return cmdCache[cmd] = new Cmd(cmd);
|
||||||
|
};
|
||||||
|
|
||||||
return Cmd;
|
return Cmd;
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
@ -157,7 +157,7 @@ var Parser = (function ParserClosure() {
|
|||||||
imageStream = this.filter(imageStream, dict, length);
|
imageStream = this.filter(imageStream, dict, length);
|
||||||
imageStream.parameters = dict;
|
imageStream.parameters = dict;
|
||||||
|
|
||||||
this.buf2 = new Cmd('EI');
|
this.buf2 = Cmd.get('EI');
|
||||||
this.shift();
|
this.shift();
|
||||||
|
|
||||||
return imageStream;
|
return imageStream;
|
||||||
@ -496,14 +496,14 @@ var Lexer = (function LexerClosure() {
|
|||||||
// array punctuation
|
// array punctuation
|
||||||
case '[':
|
case '[':
|
||||||
case ']':
|
case ']':
|
||||||
return new Cmd(ch);
|
return Cmd.get(ch);
|
||||||
// hex string or dict punctuation
|
// hex string or dict punctuation
|
||||||
case '<':
|
case '<':
|
||||||
ch = stream.lookChar();
|
ch = stream.lookChar();
|
||||||
if (ch == '<') {
|
if (ch == '<') {
|
||||||
// dict punctuation
|
// dict punctuation
|
||||||
stream.skip();
|
stream.skip();
|
||||||
return new Cmd('<<');
|
return Cmd.get('<<');
|
||||||
}
|
}
|
||||||
return this.getHexString(ch);
|
return this.getHexString(ch);
|
||||||
// dict punctuation
|
// dict punctuation
|
||||||
@ -511,11 +511,11 @@ var Lexer = (function LexerClosure() {
|
|||||||
ch = stream.lookChar();
|
ch = stream.lookChar();
|
||||||
if (ch == '>') {
|
if (ch == '>') {
|
||||||
stream.skip();
|
stream.skip();
|
||||||
return new Cmd('>>');
|
return Cmd.get('>>');
|
||||||
}
|
}
|
||||||
case '{':
|
case '{':
|
||||||
case '}':
|
case '}':
|
||||||
return new Cmd(ch);
|
return Cmd.get(ch);
|
||||||
// fall through
|
// fall through
|
||||||
case ')':
|
case ')':
|
||||||
error('Illegal character: ' + ch);
|
error('Illegal character: ' + ch);
|
||||||
@ -538,7 +538,7 @@ var Lexer = (function LexerClosure() {
|
|||||||
return false;
|
return false;
|
||||||
if (str == 'null')
|
if (str == 'null')
|
||||||
return null;
|
return null;
|
||||||
return new Cmd(str);
|
return Cmd.get(str);
|
||||||
},
|
},
|
||||||
skipToNextLine: function lexerSkipToNextLine() {
|
skipToNextLine: function lexerSkipToNextLine() {
|
||||||
var stream = this.stream;
|
var stream = this.stream;
|
||||||
|
@ -205,3 +205,15 @@
|
|||||||
});
|
});
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
// HTMLElement dataset property
|
||||||
|
(function checkDatasetProperty() {
|
||||||
|
var div = document.createElement('div');
|
||||||
|
if ('dataset' in div)
|
||||||
|
return; // dataset property exists
|
||||||
|
Object.defineProperty(HTMLElement.prototype, 'dataset', {
|
||||||
|
get: function htmlElementDatasetGetter() {
|
||||||
|
// adding dataset field to the actual object
|
||||||
|
return (this.dataset = {});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
})();
|
||||||
|
@ -970,18 +970,38 @@ window.addEventListener('keydown', function keydown(evt) {
|
|||||||
return; // ignoring if the 'controls' element is focused
|
return; // ignoring if the 'controls' element is focused
|
||||||
curElement = curElement.parentNode;
|
curElement = curElement.parentNode;
|
||||||
}
|
}
|
||||||
|
var handled = false;
|
||||||
switch (evt.keyCode) {
|
switch (evt.keyCode) {
|
||||||
case 61: // FF/Mac '='
|
case 61: // FF/Mac '='
|
||||||
case 107: // FF '+' and '='
|
case 107: // FF '+' and '='
|
||||||
case 187: // Chrome '+'
|
case 187: // Chrome '+'
|
||||||
PDFView.zoomIn();
|
PDFView.zoomIn();
|
||||||
|
handled = true;
|
||||||
break;
|
break;
|
||||||
case 109: // FF '-'
|
case 109: // FF '-'
|
||||||
case 189: // Chrome '-'
|
case 189: // Chrome '-'
|
||||||
PDFView.zoomOut();
|
PDFView.zoomOut();
|
||||||
|
handled = true;
|
||||||
break;
|
break;
|
||||||
case 48: // '0'
|
case 48: // '0'
|
||||||
PDFView.setScale(kDefaultScale, true);
|
PDFView.setScale(kDefaultScale, true);
|
||||||
|
handled = true;
|
||||||
|
break;
|
||||||
|
case 37: // left arrow
|
||||||
|
case 75: // 'k'
|
||||||
|
case 80: // 'p'
|
||||||
|
PDFView.page--;
|
||||||
|
handled = true;
|
||||||
|
break;
|
||||||
|
case 39: // right arrow
|
||||||
|
case 74: // 'j'
|
||||||
|
case 78: // 'n'
|
||||||
|
PDFView.page++;
|
||||||
|
handled = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (handled) {
|
||||||
|
evt.preventDefault();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
Loading…
Reference in New Issue
Block a user