|
|
|
@ -1236,136 +1236,6 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
@@ -1236,136 +1236,6 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
|
|
|
|
|
} |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
PartialEvaluator.optimizeQueue = |
|
|
|
|
function PartialEvaluator_optimizeQueue(queue) { |
|
|
|
|
|
|
|
|
|
function squash(array, index, howMany, element) { |
|
|
|
|
if (isArray(array)) { |
|
|
|
|
array.splice(index, howMany, element); |
|
|
|
|
} else { |
|
|
|
|
// Replace the element.
|
|
|
|
|
array[index] = element; |
|
|
|
|
// Shift everything after the element up.
|
|
|
|
|
var sub = array.subarray(index + howMany); |
|
|
|
|
array.set(sub, index + 1); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
var fnArray = queue.fnArray, argsArray = queue.argsArray; |
|
|
|
|
// grouping paintInlineImageXObject's into paintInlineImageXObjectGroup
|
|
|
|
|
// searching for (save, transform, paintInlineImageXObject, restore)+
|
|
|
|
|
var MIN_IMAGES_IN_INLINE_IMAGES_BLOCK = 10; |
|
|
|
|
var MAX_IMAGES_IN_INLINE_IMAGES_BLOCK = 200; |
|
|
|
|
var MAX_WIDTH = 1000; |
|
|
|
|
var IMAGE_PADDING = 1; |
|
|
|
|
for (var i = 0, ii = argsArray.length; i < ii; i++) { |
|
|
|
|
if (fnArray[i] === OPS.paintInlineImageXObject && |
|
|
|
|
fnArray[i - 2] === OPS.save && fnArray[i - 1] === OPS.transform && |
|
|
|
|
fnArray[i + 1] === OPS.restore) { |
|
|
|
|
var j = i - 2; |
|
|
|
|
for (i += 2; i < ii && fnArray[i - 4] === fnArray[i]; i++) { |
|
|
|
|
} |
|
|
|
|
var count = Math.min((i - j) >> 2, |
|
|
|
|
MAX_IMAGES_IN_INLINE_IMAGES_BLOCK); |
|
|
|
|
if (count < MIN_IMAGES_IN_INLINE_IMAGES_BLOCK) { |
|
|
|
|
continue; |
|
|
|
|
} |
|
|
|
|
// assuming that heights of those image is too small (~1 pixel)
|
|
|
|
|
// packing as much as possible by lines
|
|
|
|
|
var maxX = 0; |
|
|
|
|
var map = [], maxLineHeight = 0; |
|
|
|
|
var currentX = IMAGE_PADDING, currentY = IMAGE_PADDING; |
|
|
|
|
for (var q = 0; q < count; q++) { |
|
|
|
|
var transform = argsArray[j + (q << 2) + 1]; |
|
|
|
|
var img = argsArray[j + (q << 2) + 2][0]; |
|
|
|
|
if (currentX + img.width > MAX_WIDTH) { |
|
|
|
|
// starting new line
|
|
|
|
|
maxX = Math.max(maxX, currentX); |
|
|
|
|
currentY += maxLineHeight + 2 * IMAGE_PADDING; |
|
|
|
|
currentX = 0; |
|
|
|
|
maxLineHeight = 0; |
|
|
|
|
} |
|
|
|
|
map.push({ |
|
|
|
|
transform: transform, |
|
|
|
|
x: currentX, y: currentY, |
|
|
|
|
w: img.width, h: img.height |
|
|
|
|
}); |
|
|
|
|
currentX += img.width + 2 * IMAGE_PADDING; |
|
|
|
|
maxLineHeight = Math.max(maxLineHeight, img.height); |
|
|
|
|
} |
|
|
|
|
var imgWidth = Math.max(maxX, currentX) + IMAGE_PADDING; |
|
|
|
|
var imgHeight = currentY + maxLineHeight + IMAGE_PADDING; |
|
|
|
|
var imgData = new Uint8Array(imgWidth * imgHeight * 4); |
|
|
|
|
var imgRowSize = imgWidth << 2; |
|
|
|
|
for (var q = 0; q < count; q++) { |
|
|
|
|
var data = argsArray[j + (q << 2) + 2][0].data; |
|
|
|
|
// copy image by lines and extends pixels into padding
|
|
|
|
|
var rowSize = map[q].w << 2; |
|
|
|
|
var dataOffset = 0; |
|
|
|
|
var offset = (map[q].x + map[q].y * imgWidth) << 2; |
|
|
|
|
imgData.set( |
|
|
|
|
data.subarray(0, rowSize), offset - imgRowSize); |
|
|
|
|
for (var k = 0, kk = map[q].h; k < kk; k++) { |
|
|
|
|
imgData.set( |
|
|
|
|
data.subarray(dataOffset, dataOffset + rowSize), offset); |
|
|
|
|
dataOffset += rowSize; |
|
|
|
|
offset += imgRowSize; |
|
|
|
|
} |
|
|
|
|
imgData.set( |
|
|
|
|
data.subarray(dataOffset - rowSize, dataOffset), offset); |
|
|
|
|
while (offset >= 0) { |
|
|
|
|
data[offset - 4] = data[offset]; |
|
|
|
|
data[offset - 3] = data[offset + 1]; |
|
|
|
|
data[offset - 2] = data[offset + 2]; |
|
|
|
|
data[offset - 1] = data[offset + 3]; |
|
|
|
|
data[offset + rowSize] = data[offset + rowSize - 4]; |
|
|
|
|
data[offset + rowSize + 1] = data[offset + rowSize - 3]; |
|
|
|
|
data[offset + rowSize + 2] = data[offset + rowSize - 2]; |
|
|
|
|
data[offset + rowSize + 3] = data[offset + rowSize - 1]; |
|
|
|
|
offset -= imgRowSize; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
// replacing queue items
|
|
|
|
|
squash(fnArray, j, count * 4, OPS.paintInlineImageXObjectGroup); |
|
|
|
|
argsArray.splice(j, count * 4, |
|
|
|
|
[{width: imgWidth, height: imgHeight, kind: ImageKind.RGBA_32BPP, |
|
|
|
|
data: imgData}, map]); |
|
|
|
|
i = j; |
|
|
|
|
ii = argsArray.length; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
// grouping paintImageMaskXObject's into paintImageMaskXObjectGroup
|
|
|
|
|
// searching for (save, transform, paintImageMaskXObject, restore)+
|
|
|
|
|
var MIN_IMAGES_IN_MASKS_BLOCK = 10; |
|
|
|
|
var MAX_IMAGES_IN_MASKS_BLOCK = 100; |
|
|
|
|
for (var i = 0, ii = argsArray.length; i < ii; i++) { |
|
|
|
|
if (fnArray[i] === OPS.paintImageMaskXObject && |
|
|
|
|
fnArray[i - 2] === OPS.save && fnArray[i - 1] === OPS.transform && |
|
|
|
|
fnArray[i + 1] === OPS.restore) { |
|
|
|
|
var j = i - 2; |
|
|
|
|
for (i += 2; i < ii && fnArray[i - 4] === fnArray[i]; i++) { |
|
|
|
|
} |
|
|
|
|
var count = Math.min((i - j) >> 2, |
|
|
|
|
MAX_IMAGES_IN_MASKS_BLOCK); |
|
|
|
|
if (count < MIN_IMAGES_IN_MASKS_BLOCK) { |
|
|
|
|
continue; |
|
|
|
|
} |
|
|
|
|
var images = []; |
|
|
|
|
for (var q = 0; q < count; q++) { |
|
|
|
|
var transform = argsArray[j + (q << 2) + 1]; |
|
|
|
|
var maskParams = argsArray[j + (q << 2) + 2][0]; |
|
|
|
|
images.push({data: maskParams.data, width: maskParams.width, |
|
|
|
|
height: maskParams.height, transform: transform}); |
|
|
|
|
} |
|
|
|
|
// replacing queue items
|
|
|
|
|
squash(fnArray, j, count * 4, OPS.paintImageMaskXObjectGroup); |
|
|
|
|
argsArray.splice(j, count * 4, [images]); |
|
|
|
|
i = j; |
|
|
|
|
ii = argsArray.length; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
return PartialEvaluator; |
|
|
|
|
})(); |
|
|
|
|
|
|
|
|
@ -1454,7 +1324,7 @@ var OperatorList = (function OperatorListClosure() {
@@ -1454,7 +1324,7 @@ var OperatorList = (function OperatorListClosure() {
|
|
|
|
|
}, |
|
|
|
|
|
|
|
|
|
flush: function(lastChunk) { |
|
|
|
|
PartialEvaluator.optimizeQueue(this); |
|
|
|
|
new QueueOptimizer().optimize(this); |
|
|
|
|
var transfers = getTransfers(this); |
|
|
|
|
this.messageHandler.send('RenderPageChunk', { |
|
|
|
|
operatorList: { |
|
|
|
@ -1758,3 +1628,173 @@ var EvaluatorPreprocessor = (function EvaluatorPreprocessor() {
@@ -1758,3 +1628,173 @@ var EvaluatorPreprocessor = (function EvaluatorPreprocessor() {
|
|
|
|
|
}; |
|
|
|
|
return EvaluatorPreprocessor; |
|
|
|
|
})(); |
|
|
|
|
|
|
|
|
|
var QueueOptimizer = (function QueueOptimizerClosure() { |
|
|
|
|
function squash(array, index, howMany, element) { |
|
|
|
|
if (isArray(array)) { |
|
|
|
|
array.splice(index, howMany, element); |
|
|
|
|
} else { |
|
|
|
|
// Replace the element.
|
|
|
|
|
array[index] = element; |
|
|
|
|
// Shift everything after the element up.
|
|
|
|
|
var sub = array.subarray(index + howMany); |
|
|
|
|
array.set(sub, index + 1); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
function addState(parentState, pattern, fn) { |
|
|
|
|
var state = parentState; |
|
|
|
|
for (var i = 0, ii = pattern.length - 1; i < ii; i++) { |
|
|
|
|
var item = pattern[i]; |
|
|
|
|
state = state[item] || (state[item] = []); |
|
|
|
|
} |
|
|
|
|
state[pattern[pattern.length - 1]] = fn; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
var InitialState = []; |
|
|
|
|
|
|
|
|
|
addState(InitialState, |
|
|
|
|
[OPS.save, OPS.transform, OPS.paintInlineImageXObject, OPS.restore], |
|
|
|
|
function foundInlineImageGroup(context) { |
|
|
|
|
// grouping paintInlineImageXObject's into paintInlineImageXObjectGroup
|
|
|
|
|
// searching for (save, transform, paintInlineImageXObject, restore)+
|
|
|
|
|
var MIN_IMAGES_IN_INLINE_IMAGES_BLOCK = 10; |
|
|
|
|
var MAX_IMAGES_IN_INLINE_IMAGES_BLOCK = 200; |
|
|
|
|
var MAX_WIDTH = 1000; |
|
|
|
|
var IMAGE_PADDING = 1; |
|
|
|
|
|
|
|
|
|
var fnArray = context.fnArray, argsArray = context.argsArray; |
|
|
|
|
var j = context.currentOperation - 3, i = j + 4; |
|
|
|
|
var ii = context.operationsLength; |
|
|
|
|
|
|
|
|
|
for (; i < ii && fnArray[i - 4] === fnArray[i]; i++) { |
|
|
|
|
} |
|
|
|
|
var count = Math.min((i - j) >> 2, MAX_IMAGES_IN_INLINE_IMAGES_BLOCK); |
|
|
|
|
if (count < MIN_IMAGES_IN_INLINE_IMAGES_BLOCK) { |
|
|
|
|
context.currentOperation = i - 1; |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
// assuming that heights of those image is too small (~1 pixel)
|
|
|
|
|
// packing as much as possible by lines
|
|
|
|
|
var maxX = 0; |
|
|
|
|
var map = [], maxLineHeight = 0; |
|
|
|
|
var currentX = IMAGE_PADDING, currentY = IMAGE_PADDING; |
|
|
|
|
for (var q = 0; q < count; q++) { |
|
|
|
|
var transform = argsArray[j + (q << 2) + 1]; |
|
|
|
|
var img = argsArray[j + (q << 2) + 2][0]; |
|
|
|
|
if (currentX + img.width > MAX_WIDTH) { |
|
|
|
|
// starting new line
|
|
|
|
|
maxX = Math.max(maxX, currentX); |
|
|
|
|
currentY += maxLineHeight + 2 * IMAGE_PADDING; |
|
|
|
|
currentX = 0; |
|
|
|
|
maxLineHeight = 0; |
|
|
|
|
} |
|
|
|
|
map.push({ |
|
|
|
|
transform: transform, |
|
|
|
|
x: currentX, y: currentY, |
|
|
|
|
w: img.width, h: img.height |
|
|
|
|
}); |
|
|
|
|
currentX += img.width + 2 * IMAGE_PADDING; |
|
|
|
|
maxLineHeight = Math.max(maxLineHeight, img.height); |
|
|
|
|
} |
|
|
|
|
var imgWidth = Math.max(maxX, currentX) + IMAGE_PADDING; |
|
|
|
|
var imgHeight = currentY + maxLineHeight + IMAGE_PADDING; |
|
|
|
|
var imgData = new Uint8Array(imgWidth * imgHeight * 4); |
|
|
|
|
var imgRowSize = imgWidth << 2; |
|
|
|
|
for (var q = 0; q < count; q++) { |
|
|
|
|
var data = argsArray[j + (q << 2) + 2][0].data; |
|
|
|
|
// copy image by lines and extends pixels into padding
|
|
|
|
|
var rowSize = map[q].w << 2; |
|
|
|
|
var dataOffset = 0; |
|
|
|
|
var offset = (map[q].x + map[q].y * imgWidth) << 2; |
|
|
|
|
imgData.set( |
|
|
|
|
data.subarray(0, rowSize), offset - imgRowSize); |
|
|
|
|
for (var k = 0, kk = map[q].h; k < kk; k++) { |
|
|
|
|
imgData.set( |
|
|
|
|
data.subarray(dataOffset, dataOffset + rowSize), offset); |
|
|
|
|
dataOffset += rowSize; |
|
|
|
|
offset += imgRowSize; |
|
|
|
|
} |
|
|
|
|
imgData.set( |
|
|
|
|
data.subarray(dataOffset - rowSize, dataOffset), offset); |
|
|
|
|
while (offset >= 0) { |
|
|
|
|
data[offset - 4] = data[offset]; |
|
|
|
|
data[offset - 3] = data[offset + 1]; |
|
|
|
|
data[offset - 2] = data[offset + 2]; |
|
|
|
|
data[offset - 1] = data[offset + 3]; |
|
|
|
|
data[offset + rowSize] = data[offset + rowSize - 4]; |
|
|
|
|
data[offset + rowSize + 1] = data[offset + rowSize - 3]; |
|
|
|
|
data[offset + rowSize + 2] = data[offset + rowSize - 2]; |
|
|
|
|
data[offset + rowSize + 3] = data[offset + rowSize - 1]; |
|
|
|
|
offset -= imgRowSize; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
// replacing queue items
|
|
|
|
|
squash(fnArray, j, count * 4, OPS.paintInlineImageXObjectGroup); |
|
|
|
|
argsArray.splice(j, count * 4, |
|
|
|
|
[{width: imgWidth, height: imgHeight, kind: ImageKind.RGBA_32BPP, |
|
|
|
|
data: imgData}, map]); |
|
|
|
|
context.currentOperation = j; |
|
|
|
|
context.operationsLength -= count * 4 - 1; |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
addState(InitialState, |
|
|
|
|
[OPS.save, OPS.transform, OPS.paintImageMaskXObject, OPS.restore], |
|
|
|
|
function foundImageMaskGroup(context) { |
|
|
|
|
// grouping paintImageMaskXObject's into paintImageMaskXObjectGroup
|
|
|
|
|
// searching for (save, transform, paintImageMaskXObject, restore)+
|
|
|
|
|
var MIN_IMAGES_IN_MASKS_BLOCK = 10; |
|
|
|
|
var MAX_IMAGES_IN_MASKS_BLOCK = 100; |
|
|
|
|
|
|
|
|
|
var fnArray = context.fnArray, argsArray = context.argsArray; |
|
|
|
|
var j = context.currentOperation - 3, i = j + 4; |
|
|
|
|
var ii = context.operationsLength; |
|
|
|
|
|
|
|
|
|
for (; i < ii && fnArray[i - 4] === fnArray[i]; i++) { |
|
|
|
|
} |
|
|
|
|
var count = Math.min((i - j) >> 2, MAX_IMAGES_IN_MASKS_BLOCK); |
|
|
|
|
if (count < MIN_IMAGES_IN_MASKS_BLOCK) { |
|
|
|
|
context.currentOperation = i - 1; |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
var images = []; |
|
|
|
|
for (var q = 0; q < count; q++) { |
|
|
|
|
var transform = argsArray[j + (q << 2) + 1]; |
|
|
|
|
var maskParams = argsArray[j + (q << 2) + 2][0]; |
|
|
|
|
images.push({data: maskParams.data, width: maskParams.width, |
|
|
|
|
height: maskParams.height, transform: transform}); |
|
|
|
|
} |
|
|
|
|
// replacing queue items
|
|
|
|
|
squash(fnArray, j, count * 4, OPS.paintImageMaskXObjectGroup); |
|
|
|
|
argsArray.splice(j, count * 4, [images]); |
|
|
|
|
|
|
|
|
|
context.currentOperation = j; |
|
|
|
|
context.operationsLength -= count * 4 - 1; |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
function QueueOptimizer() { |
|
|
|
|
} |
|
|
|
|
QueueOptimizer.prototype = { |
|
|
|
|
optimize: function QueueOptimizer_optimize(queue) { |
|
|
|
|
var fnArray = queue.fnArray, argsArray = queue.argsArray; |
|
|
|
|
var context = { |
|
|
|
|
currentOperation: 0, |
|
|
|
|
operationsLength: argsArray.length, |
|
|
|
|
fnArray: fnArray, |
|
|
|
|
argsArray: argsArray |
|
|
|
|
}; |
|
|
|
|
var i, ii = argsArray.length; |
|
|
|
|
var state; |
|
|
|
|
for (i = 0; i < ii; i++) { |
|
|
|
|
state = (state || InitialState)[fnArray[i]]; |
|
|
|
|
if (typeof state === 'function') { // we found some handler
|
|
|
|
|
context.currentOperation = i; |
|
|
|
|
state = state(context); |
|
|
|
|
i = context.currentOperation; |
|
|
|
|
ii = context.operationsLength; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
}; |
|
|
|
|
return QueueOptimizer; |
|
|
|
|
})(); |
|
|
|
|