How to use compileType3Glyph method in wpt

Best JavaScript code snippet using wpt

canvas.js

Source:canvas.js Github

copy

Full Screen

...165 }166 }167 };168})();169function compileType3Glyph(imgData) {170 var POINT_TO_PROCESS_LIMIT = 1000;171 var width = imgData.width, height = imgData.height;172 var i, j, j0, width1 = width + 1;173 var points = new Uint8Array(width1 * (height + 1));174 var POINT_TYPES =175 new Uint8Array([0, 2, 4, 0, 1, 0, 5, 4, 8, 10, 0, 8, 0, 2, 1, 0]);176 // decodes bit-packed mask data177 var lineSize = (width + 7) & ~7, data0 = imgData.data;178 var data = new Uint8Array(lineSize * height), pos = 0, ii;179 for (i = 0, ii = data0.length; i < ii; i++) {180 var mask = 128, elem = data0[i];181 while (mask > 0) {182 data[pos++] = (elem & mask) ? 0 : 255;183 mask >>= 1;184 }185 }186 // finding iteresting points: every point is located between mask pixels,187 // so there will be points of the (width + 1)x(height + 1) grid. Every point188 // will have flags assigned based on neighboring mask pixels:189 // 4 | 8190 // --P--191 // 2 | 1192 // We are interested only in points with the flags:193 // - outside corners: 1, 2, 4, 8;194 // - inside corners: 7, 11, 13, 14;195 // - and, intersections: 5, 10.196 var count = 0;197 pos = 0;198 if (data[pos] !== 0) {199 points[0] = 1;200 ++count;201 }202 for (j = 1; j < width; j++) {203 if (data[pos] !== data[pos + 1]) {204 points[j] = data[pos] ? 2 : 1;205 ++count;206 }207 pos++;208 }209 if (data[pos] !== 0) {210 points[j] = 2;211 ++count;212 }213 for (i = 1; i < height; i++) {214 pos = i * lineSize;215 j0 = i * width1;216 if (data[pos - lineSize] !== data[pos]) {217 points[j0] = data[pos] ? 1 : 8;218 ++count;219 }220 // 'sum' is the position of the current pixel configuration in the 'TYPES'221 // array (in order 8-1-2-4, so we can use '>>2' to shift the column).222 var sum = (data[pos] ? 4 : 0) + (data[pos - lineSize] ? 8 : 0);223 for (j = 1; j < width; j++) {224 sum = (sum >> 2) + (data[pos + 1] ? 4 : 0) +225 (data[pos - lineSize + 1] ? 8 : 0);226 if (POINT_TYPES[sum]) {227 points[j0 + j] = POINT_TYPES[sum];228 ++count;229 }230 pos++;231 }232 if (data[pos - lineSize] !== data[pos]) {233 points[j0 + j] = data[pos] ? 2 : 4;234 ++count;235 }236 if (count > POINT_TO_PROCESS_LIMIT) {237 return null;238 }239 }240 pos = lineSize * (height - 1);241 j0 = i * width1;242 if (data[pos] !== 0) {243 points[j0] = 8;244 ++count;245 }246 for (j = 1; j < width; j++) {247 if (data[pos] !== data[pos + 1]) {248 points[j0 + j] = data[pos] ? 4 : 8;249 ++count;250 }251 pos++;252 }253 if (data[pos] !== 0) {254 points[j0 + j] = 4;255 ++count;256 }257 if (count > POINT_TO_PROCESS_LIMIT) {258 return null;259 }260 // building outlines261 var steps = new Int32Array([0, width1, -1, 0, -width1, 0, 0, 0, 1]);262 var outlines = [];263 for (i = 0; count && i <= height; i++) {264 var p = i * width1;265 var end = p + width;266 while (p < end && !points[p]) {267 p++;268 }269 if (p === end) {270 continue;271 }272 var coords = [p % width1, i];273 var type = points[p], p0 = p, pp;274 do {275 var step = steps[type];276 do {277 p += step;278 } while (!points[p]);279 pp = points[p];280 if (pp !== 5 && pp !== 10) {281 // set new direction282 type = pp;283 // delete mark284 points[p] = 0;285 } else { // type is 5 or 10, ie, a crossing286 // set new direction287 type = pp & ((0x33 * type) >> 4);288 // set new type for "future hit"289 points[p] &= (type >> 2 | type << 2);290 }291 coords.push(p % width1);292 coords.push((p / width1) | 0);293 --count;294 } while (p0 !== p);295 outlines.push(coords);296 --i;297 }298 var drawOutline = function(c) {299 c.save();300 // the path shall be painted in [0..1]x[0..1] space301 c.scale(1 / width, -1 / height);302 c.translate(0, -height);303 c.beginPath();304 for (var i = 0, ii = outlines.length; i < ii; i++) {305 var o = outlines[i];306 c.moveTo(o[0], o[1]);307 for (var j = 2, jj = o.length; j < jj; j += 2) {308 c.lineTo(o[j], o[j+1]);309 }310 }311 c.fill();312 c.beginPath();313 c.restore();314 };315 return drawOutline;316}317var CanvasExtraState = (function CanvasExtraStateClosure() {318 function CanvasExtraState(old) {319 // Are soft masks and alpha values shapes or opacities?320 this.alphaIsShape = false;321 this.fontSize = 0;322 this.fontSizeScale = 1;323 this.textMatrix = IDENTITY_MATRIX;324 this.textMatrixScale = 1;325 this.fontMatrix = FONT_IDENTITY_MATRIX;326 this.leading = 0;327 // Current point (in user coordinates)328 this.x = 0;329 this.y = 0;330 // Start of text line (in text coordinates)331 this.lineX = 0;332 this.lineY = 0;333 // Character and word spacing334 this.charSpacing = 0;335 this.wordSpacing = 0;336 this.textHScale = 1;337 this.textRenderingMode = TextRenderingMode.FILL;338 this.textRise = 0;339 // Default fore and background colors340 this.fillColor = '#000000';341 this.strokeColor = '#000000';342 this.patternFill = false;343 // Note: fill alpha applies to all non-stroking operations344 this.fillAlpha = 1;345 this.strokeAlpha = 1;346 this.lineWidth = 1;347 this.activeSMask = null; // nonclonable field (see the save method below)348 this.old = old;349 }350 CanvasExtraState.prototype = {351 clone: function CanvasExtraState_clone() {352 return Object.create(this);353 },354 setCurrentPoint: function CanvasExtraState_setCurrentPoint(x, y) {355 this.x = x;356 this.y = y;357 }358 };359 return CanvasExtraState;360})();361var CanvasGraphics = (function CanvasGraphicsClosure() {362 // Defines the time the executeOperatorList is going to be executing363 // before it stops and shedules a continue of execution.364 var EXECUTION_TIME = 15;365 // Defines the number of steps before checking the execution time366 var EXECUTION_STEPS = 10;367 function CanvasGraphics(canvasCtx, commonObjs, objs, imageLayer) {368 this.ctx = canvasCtx;369 this.current = new CanvasExtraState();370 this.stateStack = [];371 this.pendingClip = null;372 this.pendingEOFill = false;373 this.res = null;374 this.xobjs = null;375 this.commonObjs = commonObjs;376 this.objs = objs;377 this.imageLayer = imageLayer;378 this.groupStack = [];379 this.processingType3 = null;380 // Patterns are painted relative to the initial page/form transform, see pdf381 // spec 8.7.2 NOTE 1.382 this.baseTransform = null;383 this.baseTransformStack = [];384 this.groupLevel = 0;385 this.smaskStack = [];386 this.smaskCounter = 0;387 this.tempSMask = null;388 if (canvasCtx) {389 // NOTE: if mozCurrentTransform is polyfilled, then the current state of390 // the transformation must already be set in canvasCtx._transformMatrix.391 addContextCurrentTransform(canvasCtx);392 }393 this.cachedGetSinglePixelWidth = null;394 }395 function putBinaryImageData(ctx, imgData) {396 if (typeof ImageData !== 'undefined' && imgData instanceof ImageData) {397 ctx.putImageData(imgData, 0, 0);398 return;399 }400 // Put the image data to the canvas in chunks, rather than putting the401 // whole image at once. This saves JS memory, because the ImageData object402 // is smaller. It also possibly saves C++ memory within the implementation403 // of putImageData(). (E.g. in Firefox we make two short-lived copies of404 // the data passed to putImageData()). |n| shouldn't be too small, however,405 // because too many putImageData() calls will slow things down.406 //407 // Note: as written, if the last chunk is partial, the putImageData() call408 // will (conceptually) put pixels past the bounds of the canvas. But409 // that's ok; any such pixels are ignored.410 var height = imgData.height, width = imgData.width;411 var partialChunkHeight = height % FULL_CHUNK_HEIGHT;412 var fullChunks = (height - partialChunkHeight) / FULL_CHUNK_HEIGHT;413 var totalChunks = partialChunkHeight === 0 ? fullChunks : fullChunks + 1;414 var chunkImgData = ctx.createImageData(width, FULL_CHUNK_HEIGHT);415 var srcPos = 0, destPos;416 var src = imgData.data;417 var dest = chunkImgData.data;418 var i, j, thisChunkHeight, elemsInThisChunk;419 // There are multiple forms in which the pixel data can be passed, and420 // imgData.kind tells us which one this is.421 if (imgData.kind === ImageKind.GRAYSCALE_1BPP) {422 // Grayscale, 1 bit per pixel (i.e. black-and-white).423 var srcLength = src.byteLength;424 var dest32 = PDFJS.hasCanvasTypedArrays ? new Uint32Array(dest.buffer) :425 new Uint32ArrayView(dest);426 var dest32DataLength = dest32.length;427 var fullSrcDiff = (width + 7) >> 3;428 var white = 0xFFFFFFFF;429 var black = (PDFJS.isLittleEndian || !PDFJS.hasCanvasTypedArrays) ?430 0xFF000000 : 0x000000FF;431 for (i = 0; i < totalChunks; i++) {432 thisChunkHeight =433 (i < fullChunks) ? FULL_CHUNK_HEIGHT : partialChunkHeight;434 destPos = 0;435 for (j = 0; j < thisChunkHeight; j++) {436 var srcDiff = srcLength - srcPos;437 var k = 0;438 var kEnd = (srcDiff > fullSrcDiff) ? width : srcDiff * 8 - 7;439 var kEndUnrolled = kEnd & ~7;440 var mask = 0;441 var srcByte = 0;442 for (; k < kEndUnrolled; k += 8) {443 srcByte = src[srcPos++];444 dest32[destPos++] = (srcByte & 128) ? white : black;445 dest32[destPos++] = (srcByte & 64) ? white : black;446 dest32[destPos++] = (srcByte & 32) ? white : black;447 dest32[destPos++] = (srcByte & 16) ? white : black;448 dest32[destPos++] = (srcByte & 8) ? white : black;449 dest32[destPos++] = (srcByte & 4) ? white : black;450 dest32[destPos++] = (srcByte & 2) ? white : black;451 dest32[destPos++] = (srcByte & 1) ? white : black;452 }453 for (; k < kEnd; k++) {454 if (mask === 0) {455 srcByte = src[srcPos++];456 mask = 128;457 }458 dest32[destPos++] = (srcByte & mask) ? white : black;459 mask >>= 1;460 }461 }462 // We ran out of input. Make all remaining pixels transparent.463 while (destPos < dest32DataLength) {464 dest32[destPos++] = 0;465 }466 ctx.putImageData(chunkImgData, 0, i * FULL_CHUNK_HEIGHT);467 }468 } else if (imgData.kind === ImageKind.RGBA_32BPP) {469 // RGBA, 32-bits per pixel.470 j = 0;471 elemsInThisChunk = width * FULL_CHUNK_HEIGHT * 4;472 for (i = 0; i < fullChunks; i++) {473 dest.set(src.subarray(srcPos, srcPos + elemsInThisChunk));474 srcPos += elemsInThisChunk;475 ctx.putImageData(chunkImgData, 0, j);476 j += FULL_CHUNK_HEIGHT;477 }478 if (i < totalChunks) {479 elemsInThisChunk = width * partialChunkHeight * 4;480 dest.set(src.subarray(srcPos, srcPos + elemsInThisChunk));481 ctx.putImageData(chunkImgData, 0, j);482 }483 } else if (imgData.kind === ImageKind.RGB_24BPP) {484 // RGB, 24-bits per pixel.485 thisChunkHeight = FULL_CHUNK_HEIGHT;486 elemsInThisChunk = width * thisChunkHeight;487 for (i = 0; i < totalChunks; i++) {488 if (i >= fullChunks) {489 thisChunkHeight = partialChunkHeight;490 elemsInThisChunk = width * thisChunkHeight;491 }492 destPos = 0;493 for (j = elemsInThisChunk; j--;) {494 dest[destPos++] = src[srcPos++];495 dest[destPos++] = src[srcPos++];496 dest[destPos++] = src[srcPos++];497 dest[destPos++] = 255;498 }499 ctx.putImageData(chunkImgData, 0, i * FULL_CHUNK_HEIGHT);500 }501 } else {502 error('bad image kind: ' + imgData.kind);503 }504 }505 function putBinaryImageMask(ctx, imgData) {506 var height = imgData.height, width = imgData.width;507 var partialChunkHeight = height % FULL_CHUNK_HEIGHT;508 var fullChunks = (height - partialChunkHeight) / FULL_CHUNK_HEIGHT;509 var totalChunks = partialChunkHeight === 0 ? fullChunks : fullChunks + 1;510 var chunkImgData = ctx.createImageData(width, FULL_CHUNK_HEIGHT);511 var srcPos = 0;512 var src = imgData.data;513 var dest = chunkImgData.data;514 for (var i = 0; i < totalChunks; i++) {515 var thisChunkHeight =516 (i < fullChunks) ? FULL_CHUNK_HEIGHT : partialChunkHeight;517 // Expand the mask so it can be used by the canvas. Any required518 // inversion has already been handled.519 var destPos = 3; // alpha component offset520 for (var j = 0; j < thisChunkHeight; j++) {521 var mask = 0;522 for (var k = 0; k < width; k++) {523 if (!mask) {524 var elem = src[srcPos++];525 mask = 128;526 }527 dest[destPos] = (elem & mask) ? 0 : 255;528 destPos += 4;529 mask >>= 1;530 }531 }532 ctx.putImageData(chunkImgData, 0, i * FULL_CHUNK_HEIGHT);533 }534 }535 function copyCtxState(sourceCtx, destCtx) {536 var properties = ['strokeStyle', 'fillStyle', 'fillRule', 'globalAlpha',537 'lineWidth', 'lineCap', 'lineJoin', 'miterLimit',538 'globalCompositeOperation', 'font'];539 for (var i = 0, ii = properties.length; i < ii; i++) {540 var property = properties[i];541 if (sourceCtx[property] !== undefined) {542 destCtx[property] = sourceCtx[property];543 }544 }545 if (sourceCtx.setLineDash !== undefined) {546 destCtx.setLineDash(sourceCtx.getLineDash());547 destCtx.lineDashOffset = sourceCtx.lineDashOffset;548 } else if (sourceCtx.mozDashOffset !== undefined) {549 destCtx.mozDash = sourceCtx.mozDash;550 destCtx.mozDashOffset = sourceCtx.mozDashOffset;551 }552 }553 function composeSMaskBackdrop(bytes, r0, g0, b0) {554 var length = bytes.length;555 for (var i = 3; i < length; i += 4) {556 var alpha = bytes[i];557 if (alpha === 0) {558 bytes[i - 3] = r0;559 bytes[i - 2] = g0;560 bytes[i - 1] = b0;561 } else if (alpha < 255) {562 var alpha_ = 255 - alpha;563 bytes[i - 3] = (bytes[i - 3] * alpha + r0 * alpha_) >> 8;564 bytes[i - 2] = (bytes[i - 2] * alpha + g0 * alpha_) >> 8;565 bytes[i - 1] = (bytes[i - 1] * alpha + b0 * alpha_) >> 8;566 }567 }568 }569 function composeSMaskAlpha(maskData, layerData) {570 var length = maskData.length;571 var scale = 1 / 255;572 for (var i = 3; i < length; i += 4) {573 var alpha = maskData[i];574 layerData[i] = (layerData[i] * alpha * scale) | 0;575 }576 }577 function composeSMaskLuminosity(maskData, layerData) {578 var length = maskData.length;579 for (var i = 3; i < length; i += 4) {580 var y = (maskData[i - 3] * 77) + // * 0.3 / 255 * 0x10000581 (maskData[i - 2] * 152) + // * 0.59 ....582 (maskData[i - 1] * 28); // * 0.11 ....583 layerData[i] = (layerData[i] * y) >> 16;584 }585 }586 function genericComposeSMask(maskCtx, layerCtx, width, height,587 subtype, backdrop) {588 var hasBackdrop = !!backdrop;589 var r0 = hasBackdrop ? backdrop[0] : 0;590 var g0 = hasBackdrop ? backdrop[1] : 0;591 var b0 = hasBackdrop ? backdrop[2] : 0;592 var composeFn;593 if (subtype === 'Luminosity') {594 composeFn = composeSMaskLuminosity;595 } else {596 composeFn = composeSMaskAlpha;597 }598 // processing image in chunks to save memory599 var PIXELS_TO_PROCESS = 1048576;600 var chunkSize = Math.min(height, Math.ceil(PIXELS_TO_PROCESS / width));601 for (var row = 0; row < height; row += chunkSize) {602 var chunkHeight = Math.min(chunkSize, height - row);603 var maskData = maskCtx.getImageData(0, row, width, chunkHeight);604 var layerData = layerCtx.getImageData(0, row, width, chunkHeight);605 if (hasBackdrop) {606 composeSMaskBackdrop(maskData.data, r0, g0, b0);607 }608 composeFn(maskData.data, layerData.data);609 maskCtx.putImageData(layerData, 0, row);610 }611 }612 function composeSMask(ctx, smask, layerCtx) {613 var mask = smask.canvas;614 var maskCtx = smask.context;615 ctx.setTransform(smask.scaleX, 0, 0, smask.scaleY,616 smask.offsetX, smask.offsetY);617 var backdrop = smask.backdrop || null;618 if (WebGLUtils.isEnabled) {619 var composed = WebGLUtils.composeSMask(layerCtx.canvas, mask,620 {subtype: smask.subtype, backdrop: backdrop});621 ctx.setTransform(1, 0, 0, 1, 0, 0);622 ctx.drawImage(composed, smask.offsetX, smask.offsetY);623 return;624 }625 genericComposeSMask(maskCtx, layerCtx, mask.width, mask.height,626 smask.subtype, backdrop);627 ctx.drawImage(mask, 0, 0);628 }629 var LINE_CAP_STYLES = ['butt', 'round', 'square'];630 var LINE_JOIN_STYLES = ['miter', 'round', 'bevel'];631 var NORMAL_CLIP = {};632 var EO_CLIP = {};633 CanvasGraphics.prototype = {634 beginDrawing: function CanvasGraphics_beginDrawing(viewport, transparency) {635 // For pdfs that use blend modes we have to clear the canvas else certain636 // blend modes can look wrong since we'd be blending with a white637 // backdrop. The problem with a transparent backdrop though is we then638 // don't get sub pixel anti aliasing on text, so we fill with white if639 // we can.640 var width = this.ctx.canvas.width;641 var height = this.ctx.canvas.height;642 if (transparency) {643 this.ctx.clearRect(0, 0, width, height);644 } else {645 this.ctx.mozOpaque = true;646 this.ctx.save();647 this.ctx.fillStyle = 'rgb(255, 255, 255)';648 this.ctx.fillRect(0, 0, width, height);649 this.ctx.restore();650 }651 var transform = viewport.transform;652 this.ctx.save();653 this.ctx.transform.apply(this.ctx, transform);654 this.baseTransform = this.ctx.mozCurrentTransform.slice();655 if (this.imageLayer) {656 this.imageLayer.beginLayout();657 }658 },659 executeOperatorList: function CanvasGraphics_executeOperatorList(660 operatorList,661 executionStartIdx, continueCallback,662 stepper) {663 var argsArray = operatorList.argsArray;664 var fnArray = operatorList.fnArray;665 var i = executionStartIdx || 0;666 var argsArrayLen = argsArray.length;667 // Sometimes the OperatorList to execute is empty.668 if (argsArrayLen === i) {669 return i;670 }671 var chunkOperations = (argsArrayLen - i > EXECUTION_STEPS &&672 typeof continueCallback === 'function');673 var endTime = chunkOperations ? Date.now() + EXECUTION_TIME : 0;674 var steps = 0;675 var commonObjs = this.commonObjs;676 var objs = this.objs;677 var fnId;678 while (true) {679 if (stepper !== undefined && i === stepper.nextBreakPoint) {680 stepper.breakIt(i, continueCallback);681 return i;682 }683 fnId = fnArray[i];684 if (fnId !== OPS.dependency) {685 this[fnId].apply(this, argsArray[i]);686 } else {687 var deps = argsArray[i];688 for (var n = 0, nn = deps.length; n < nn; n++) {689 var depObjId = deps[n];690 var common = depObjId[0] === 'g' && depObjId[1] === '_';691 var objsPool = common ? commonObjs : objs;692 // If the promise isn't resolved yet, add the continueCallback693 // to the promise and bail out.694 if (!objsPool.isResolved(depObjId)) {695 objsPool.get(depObjId, continueCallback);696 return i;697 }698 }699 }700 i++;701 // If the entire operatorList was executed, stop as were done.702 if (i === argsArrayLen) {703 return i;704 }705 // If the execution took longer then a certain amount of time and706 // `continueCallback` is specified, interrupt the execution.707 if (chunkOperations && ++steps > EXECUTION_STEPS) {708 if (Date.now() > endTime) {709 continueCallback();710 return i;711 }712 steps = 0;713 }714 // If the operatorList isn't executed completely yet OR the execution715 // time was short enough, do another execution round.716 }717 },718 endDrawing: function CanvasGraphics_endDrawing() {719 this.ctx.restore();720 CachedCanvases.clear();721 WebGLUtils.clear();722 if (this.imageLayer) {723 this.imageLayer.endLayout();724 }725 },726 // Graphics state727 setLineWidth: function CanvasGraphics_setLineWidth(width) {728 this.current.lineWidth = width;729 this.ctx.lineWidth = width;730 },731 setLineCap: function CanvasGraphics_setLineCap(style) {732 this.ctx.lineCap = LINE_CAP_STYLES[style];733 },734 setLineJoin: function CanvasGraphics_setLineJoin(style) {735 this.ctx.lineJoin = LINE_JOIN_STYLES[style];736 },737 setMiterLimit: function CanvasGraphics_setMiterLimit(limit) {738 this.ctx.miterLimit = limit;739 },740 setDash: function CanvasGraphics_setDash(dashArray, dashPhase) {741 var ctx = this.ctx;742 if (ctx.setLineDash !== undefined) {743 ctx.setLineDash(dashArray);744 ctx.lineDashOffset = dashPhase;745 } else {746 ctx.mozDash = dashArray;747 ctx.mozDashOffset = dashPhase;748 }749 },750 setRenderingIntent: function CanvasGraphics_setRenderingIntent(intent) {751 // Maybe if we one day fully support color spaces this will be important752 // for now we can ignore.753 // TODO set rendering intent?754 },755 setFlatness: function CanvasGraphics_setFlatness(flatness) {756 // There's no way to control this with canvas, but we can safely ignore.757 // TODO set flatness?758 },759 setGState: function CanvasGraphics_setGState(states) {760 for (var i = 0, ii = states.length; i < ii; i++) {761 var state = states[i];762 var key = state[0];763 var value = state[1];764 switch (key) {765 case 'LW':766 this.setLineWidth(value);767 break;768 case 'LC':769 this.setLineCap(value);770 break;771 case 'LJ':772 this.setLineJoin(value);773 break;774 case 'ML':775 this.setMiterLimit(value);776 break;777 case 'D':778 this.setDash(value[0], value[1]);779 break;780 case 'RI':781 this.setRenderingIntent(value);782 break;783 case 'FL':784 this.setFlatness(value);785 break;786 case 'Font':787 this.setFont(value[0], value[1]);788 break;789 case 'CA':790 this.current.strokeAlpha = state[1];791 break;792 case 'ca':793 this.current.fillAlpha = state[1];794 this.ctx.globalAlpha = state[1];795 break;796 case 'BM':797 if (value && value.name && (value.name !== 'Normal')) {798 var mode = value.name.replace(/([A-Z])/g,799 function(c) {800 return '-' + c.toLowerCase();801 }802 ).substring(1);803 this.ctx.globalCompositeOperation = mode;804 if (this.ctx.globalCompositeOperation !== mode) {805 warn('globalCompositeOperation "' + mode +806 '" is not supported');807 }808 } else {809 this.ctx.globalCompositeOperation = 'source-over';810 }811 break;812 case 'SMask':813 if (this.current.activeSMask) {814 this.endSMaskGroup();815 }816 this.current.activeSMask = value ? this.tempSMask : null;817 if (this.current.activeSMask) {818 this.beginSMaskGroup();819 }820 this.tempSMask = null;821 break;822 }823 }824 },825 beginSMaskGroup: function CanvasGraphics_beginSMaskGroup() {826 var activeSMask = this.current.activeSMask;827 var drawnWidth = activeSMask.canvas.width;828 var drawnHeight = activeSMask.canvas.height;829 var cacheId = 'smaskGroupAt' + this.groupLevel;830 var scratchCanvas = CachedCanvases.getCanvas(831 cacheId, drawnWidth, drawnHeight, true);832 var currentCtx = this.ctx;833 var currentTransform = currentCtx.mozCurrentTransform;834 this.ctx.save();835 var groupCtx = scratchCanvas.context;836 groupCtx.scale(1 / activeSMask.scaleX, 1 / activeSMask.scaleY);837 groupCtx.translate(-activeSMask.offsetX, -activeSMask.offsetY);838 groupCtx.transform.apply(groupCtx, currentTransform);839 copyCtxState(currentCtx, groupCtx);840 this.ctx = groupCtx;841 this.setGState([842 ['BM', 'Normal'],843 ['ca', 1],844 ['CA', 1]845 ]);846 this.groupStack.push(currentCtx);847 this.groupLevel++;848 },849 endSMaskGroup: function CanvasGraphics_endSMaskGroup() {850 var groupCtx = this.ctx;851 this.groupLevel--;852 this.ctx = this.groupStack.pop();853 composeSMask(this.ctx, this.current.activeSMask, groupCtx);854 this.ctx.restore();855 },856 save: function CanvasGraphics_save() {857 this.ctx.save();858 var old = this.current;859 this.stateStack.push(old);860 this.current = old.clone();861 this.current.activeSMask = null;862 },863 restore: function CanvasGraphics_restore() {864 if (this.stateStack.length !== 0) {865 if (this.current.activeSMask !== null) {866 this.endSMaskGroup();867 }868 this.current = this.stateStack.pop();869 this.ctx.restore();870 this.cachedGetSinglePixelWidth = null;871 }872 },873 transform: function CanvasGraphics_transform(a, b, c, d, e, f) {874 this.ctx.transform(a, b, c, d, e, f);875 this.cachedGetSinglePixelWidth = null;876 },877 // Path878 constructPath: function CanvasGraphics_constructPath(ops, args) {879 var ctx = this.ctx;880 var current = this.current;881 var x = current.x, y = current.y;882 for (var i = 0, j = 0, ii = ops.length; i < ii; i++) {883 switch (ops[i] | 0) {884 case OPS.rectangle:885 x = args[j++];886 y = args[j++];887 var width = args[j++];888 var height = args[j++];889 if (width === 0) {890 width = this.getSinglePixelWidth();891 }892 if (height === 0) {893 height = this.getSinglePixelWidth();894 }895 var xw = x + width;896 var yh = y + height;897 this.ctx.moveTo(x, y);898 this.ctx.lineTo(xw, y);899 this.ctx.lineTo(xw, yh);900 this.ctx.lineTo(x, yh);901 this.ctx.lineTo(x, y);902 this.ctx.closePath();903 break;904 case OPS.moveTo:905 x = args[j++];906 y = args[j++];907 ctx.moveTo(x, y);908 break;909 case OPS.lineTo:910 x = args[j++];911 y = args[j++];912 ctx.lineTo(x, y);913 break;914 case OPS.curveTo:915 x = args[j + 4];916 y = args[j + 5];917 ctx.bezierCurveTo(args[j], args[j + 1], args[j + 2], args[j + 3],918 x, y);919 j += 6;920 break;921 case OPS.curveTo2:922 ctx.bezierCurveTo(x, y, args[j], args[j + 1],923 args[j + 2], args[j + 3]);924 x = args[j + 2];925 y = args[j + 3];926 j += 4;927 break;928 case OPS.curveTo3:929 x = args[j + 2];930 y = args[j + 3];931 ctx.bezierCurveTo(args[j], args[j + 1], x, y, x, y);932 j += 4;933 break;934 case OPS.closePath:935 ctx.closePath();936 break;937 }938 }939 current.setCurrentPoint(x, y);940 },941 closePath: function CanvasGraphics_closePath() {942 this.ctx.closePath();943 },944 stroke: function CanvasGraphics_stroke(consumePath) {945 consumePath = typeof consumePath !== 'undefined' ? consumePath : true;946 var ctx = this.ctx;947 var strokeColor = this.current.strokeColor;948 // Prevent drawing too thin lines by enforcing a minimum line width.949 ctx.lineWidth = Math.max(this.getSinglePixelWidth() * MIN_WIDTH_FACTOR,950 this.current.lineWidth);951 // For stroke we want to temporarily change the global alpha to the952 // stroking alpha.953 ctx.globalAlpha = this.current.strokeAlpha;954 if (strokeColor && strokeColor.hasOwnProperty('type') &&955 strokeColor.type === 'Pattern') {956 // for patterns, we transform to pattern space, calculate957 // the pattern, call stroke, and restore to user space958 ctx.save();959 ctx.strokeStyle = strokeColor.getPattern(ctx, this);960 ctx.stroke();961 ctx.restore();962 } else {963 ctx.stroke();964 }965 if (consumePath) {966 this.consumePath();967 }968 // Restore the global alpha to the fill alpha969 ctx.globalAlpha = this.current.fillAlpha;970 },971 closeStroke: function CanvasGraphics_closeStroke() {972 this.closePath();973 this.stroke();974 },975 fill: function CanvasGraphics_fill(consumePath) {976 consumePath = typeof consumePath !== 'undefined' ? consumePath : true;977 var ctx = this.ctx;978 var fillColor = this.current.fillColor;979 var isPatternFill = this.current.patternFill;980 var needRestore = false;981 if (isPatternFill) {982 ctx.save();983 ctx.fillStyle = fillColor.getPattern(ctx, this);984 needRestore = true;985 }986 if (this.pendingEOFill) {987 if (ctx.mozFillRule !== undefined) {988 ctx.mozFillRule = 'evenodd';989 ctx.fill();990 ctx.mozFillRule = 'nonzero';991 } else {992 try {993 ctx.fill('evenodd');994 } catch (ex) {995 // shouldn't really happen, but browsers might think differently996 ctx.fill();997 }998 }999 this.pendingEOFill = false;1000 } else {1001 ctx.fill();1002 }1003 if (needRestore) {1004 ctx.restore();1005 }1006 if (consumePath) {1007 this.consumePath();1008 }1009 },1010 eoFill: function CanvasGraphics_eoFill() {1011 this.pendingEOFill = true;1012 this.fill();1013 },1014 fillStroke: function CanvasGraphics_fillStroke() {1015 this.fill(false);1016 this.stroke(false);1017 this.consumePath();1018 },1019 eoFillStroke: function CanvasGraphics_eoFillStroke() {1020 this.pendingEOFill = true;1021 this.fillStroke();1022 },1023 closeFillStroke: function CanvasGraphics_closeFillStroke() {1024 this.closePath();1025 this.fillStroke();1026 },1027 closeEOFillStroke: function CanvasGraphics_closeEOFillStroke() {1028 this.pendingEOFill = true;1029 this.closePath();1030 this.fillStroke();1031 },1032 endPath: function CanvasGraphics_endPath() {1033 this.consumePath();1034 },1035 // Clipping1036 clip: function CanvasGraphics_clip() {1037 this.pendingClip = NORMAL_CLIP;1038 },1039 eoClip: function CanvasGraphics_eoClip() {1040 this.pendingClip = EO_CLIP;1041 },1042 // Text1043 beginText: function CanvasGraphics_beginText() {1044 this.current.textMatrix = IDENTITY_MATRIX;1045 this.current.textMatrixScale = 1;1046 this.current.x = this.current.lineX = 0;1047 this.current.y = this.current.lineY = 0;1048 },1049 endText: function CanvasGraphics_endText() {1050 var paths = this.pendingTextPaths;1051 var ctx = this.ctx;1052 if (paths === undefined) {1053 ctx.beginPath();1054 return;1055 }1056 ctx.save();1057 ctx.beginPath();1058 for (var i = 0; i < paths.length; i++) {1059 var path = paths[i];1060 ctx.setTransform.apply(ctx, path.transform);1061 ctx.translate(path.x, path.y);1062 path.addToPath(ctx, path.fontSize);1063 }1064 ctx.restore();1065 ctx.clip();1066 ctx.beginPath();1067 delete this.pendingTextPaths;1068 },1069 setCharSpacing: function CanvasGraphics_setCharSpacing(spacing) {1070 this.current.charSpacing = spacing;1071 },1072 setWordSpacing: function CanvasGraphics_setWordSpacing(spacing) {1073 this.current.wordSpacing = spacing;1074 },1075 setHScale: function CanvasGraphics_setHScale(scale) {1076 this.current.textHScale = scale / 100;1077 },1078 setLeading: function CanvasGraphics_setLeading(leading) {1079 this.current.leading = -leading;1080 },1081 setFont: function CanvasGraphics_setFont(fontRefName, size) {1082 var fontObj = this.commonObjs.get(fontRefName);1083 var current = this.current;1084 if (!fontObj) {1085 error('Can\'t find font for ' + fontRefName);1086 }1087 current.fontMatrix = (fontObj.fontMatrix ?1088 fontObj.fontMatrix : FONT_IDENTITY_MATRIX);1089 // A valid matrix needs all main diagonal elements to be non-zero1090 // This also ensures we bypass FF bugzilla bug #719844.1091 if (current.fontMatrix[0] === 0 ||1092 current.fontMatrix[3] === 0) {1093 warn('Invalid font matrix for font ' + fontRefName);1094 }1095 // The spec for Tf (setFont) says that 'size' specifies the font 'scale',1096 // and in some docs this can be negative (inverted x-y axes).1097 if (size < 0) {1098 size = -size;1099 current.fontDirection = -1;1100 } else {1101 current.fontDirection = 1;1102 }1103 this.current.font = fontObj;1104 this.current.fontSize = size;1105 if (fontObj.isType3Font) {1106 return; // we don't need ctx.font for Type3 fonts1107 }1108 var name = fontObj.loadedName || 'sans-serif';1109 var bold = fontObj.black ? (fontObj.bold ? 'bolder' : 'bold') :1110 (fontObj.bold ? 'bold' : 'normal');1111 var italic = fontObj.italic ? 'italic' : 'normal';1112 var typeface = '"' + name + '", ' + fontObj.fallbackName;1113 // Some font backends cannot handle fonts below certain size.1114 // Keeping the font at minimal size and using the fontSizeScale to change1115 // the current transformation matrix before the fillText/strokeText.1116 // See https://bugzilla.mozilla.org/show_bug.cgi?id=7262271117 var browserFontSize = size < MIN_FONT_SIZE ? MIN_FONT_SIZE :1118 size > MAX_FONT_SIZE ? MAX_FONT_SIZE : size;1119 this.current.fontSizeScale = size / browserFontSize;1120 var rule = italic + ' ' + bold + ' ' + browserFontSize + 'px ' + typeface;1121 this.ctx.font = rule;1122 },1123 setTextRenderingMode: function CanvasGraphics_setTextRenderingMode(mode) {1124 this.current.textRenderingMode = mode;1125 },1126 setTextRise: function CanvasGraphics_setTextRise(rise) {1127 this.current.textRise = rise;1128 },1129 moveText: function CanvasGraphics_moveText(x, y) {1130 this.current.x = this.current.lineX += x;1131 this.current.y = this.current.lineY += y;1132 },1133 setLeadingMoveText: function CanvasGraphics_setLeadingMoveText(x, y) {1134 this.setLeading(-y);1135 this.moveText(x, y);1136 },1137 setTextMatrix: function CanvasGraphics_setTextMatrix(a, b, c, d, e, f) {1138 this.current.textMatrix = [a, b, c, d, e, f];1139 this.current.textMatrixScale = Math.sqrt(a * a + b * b);1140 this.current.x = this.current.lineX = 0;1141 this.current.y = this.current.lineY = 0;1142 },1143 nextLine: function CanvasGraphics_nextLine() {1144 this.moveText(0, this.current.leading);1145 },1146 paintChar: function CanvasGraphics_paintChar(character, x, y) {1147 var ctx = this.ctx;1148 var current = this.current;1149 var font = current.font;1150 var textRenderingMode = current.textRenderingMode;1151 var fontSize = current.fontSize / current.fontSizeScale;1152 var fillStrokeMode = textRenderingMode &1153 TextRenderingMode.FILL_STROKE_MASK;1154 var isAddToPathSet = !!(textRenderingMode &1155 TextRenderingMode.ADD_TO_PATH_FLAG);1156 var addToPath;1157 if (font.disableFontFace || isAddToPathSet) {1158 addToPath = font.getPathGenerator(this.commonObjs, character);1159 }1160 if (font.disableFontFace) {1161 ctx.save();1162 ctx.translate(x, y);1163 ctx.beginPath();1164 addToPath(ctx, fontSize);1165 if (fillStrokeMode === TextRenderingMode.FILL ||1166 fillStrokeMode === TextRenderingMode.FILL_STROKE) {1167 ctx.fill();1168 }1169 if (fillStrokeMode === TextRenderingMode.STROKE ||1170 fillStrokeMode === TextRenderingMode.FILL_STROKE) {1171 ctx.stroke();1172 }1173 ctx.restore();1174 } else {1175 if (fillStrokeMode === TextRenderingMode.FILL ||1176 fillStrokeMode === TextRenderingMode.FILL_STROKE) {1177 ctx.fillText(character, x, y);1178 }1179 if (fillStrokeMode === TextRenderingMode.STROKE ||1180 fillStrokeMode === TextRenderingMode.FILL_STROKE) {1181 ctx.strokeText(character, x, y);1182 }1183 }1184 if (isAddToPathSet) {1185 var paths = this.pendingTextPaths || (this.pendingTextPaths = []);1186 paths.push({1187 transform: ctx.mozCurrentTransform,1188 x: x,1189 y: y,1190 fontSize: fontSize,1191 addToPath: addToPath1192 });1193 }1194 },1195 get isFontSubpixelAAEnabled() {1196 // Checks if anti-aliasing is enabled when scaled text is painted.1197 // On Windows GDI scaled fonts looks bad.1198 var ctx = document.createElement('canvas').getContext('2d');1199 ctx.scale(1.5, 1);1200 ctx.fillText('I', 0, 10);1201 var data = ctx.getImageData(0, 0, 10, 10).data;1202 var enabled = false;1203 for (var i = 3; i < data.length; i += 4) {1204 if (data[i] > 0 && data[i] < 255) {1205 enabled = true;1206 break;1207 }1208 }1209 return shadow(this, 'isFontSubpixelAAEnabled', enabled);1210 },1211 showText: function CanvasGraphics_showText(glyphs) {1212 var current = this.current;1213 var font = current.font;1214 if (font.isType3Font) {1215 return this.showType3Text(glyphs);1216 }1217 var fontSize = current.fontSize;1218 if (fontSize === 0) {1219 return;1220 }1221 var ctx = this.ctx;1222 var fontSizeScale = current.fontSizeScale;1223 var charSpacing = current.charSpacing;1224 var wordSpacing = current.wordSpacing;1225 var fontDirection = current.fontDirection;1226 var textHScale = current.textHScale * fontDirection;1227 var glyphsLength = glyphs.length;1228 var vertical = font.vertical;1229 var defaultVMetrics = font.defaultVMetrics;1230 var widthAdvanceScale = fontSize * current.fontMatrix[0];1231 var simpleFillText =1232 current.textRenderingMode === TextRenderingMode.FILL &&1233 !font.disableFontFace;1234 ctx.save();1235 ctx.transform.apply(ctx, current.textMatrix);1236 ctx.translate(current.x, current.y + current.textRise);1237 if (fontDirection > 0) {1238 ctx.scale(textHScale, -1);1239 } else {1240 ctx.scale(textHScale, 1);1241 }1242 var lineWidth = current.lineWidth;1243 var scale = current.textMatrixScale;1244 if (scale === 0 || lineWidth === 0) {1245 var fillStrokeMode = current.textRenderingMode &1246 TextRenderingMode.FILL_STROKE_MASK;1247 if (fillStrokeMode === TextRenderingMode.STROKE ||1248 fillStrokeMode === TextRenderingMode.FILL_STROKE) {1249 this.cachedGetSinglePixelWidth = null;1250 lineWidth = this.getSinglePixelWidth() * MIN_WIDTH_FACTOR;1251 }1252 } else {1253 lineWidth /= scale;1254 }1255 if (fontSizeScale !== 1.0) {1256 ctx.scale(fontSizeScale, fontSizeScale);1257 lineWidth /= fontSizeScale;1258 }1259 ctx.lineWidth = lineWidth;1260 var x = 0, i;1261 for (i = 0; i < glyphsLength; ++i) {1262 var glyph = glyphs[i];1263 if (glyph === null) {1264 // word break1265 x += fontDirection * wordSpacing;1266 continue;1267 } else if (isNum(glyph)) {1268 x += -glyph * fontSize * 0.001;1269 continue;1270 }1271 var restoreNeeded = false;1272 var character = glyph.fontChar;1273 var accent = glyph.accent;1274 var scaledX, scaledY, scaledAccentX, scaledAccentY;1275 var width = glyph.width;1276 if (vertical) {1277 var vmetric, vx, vy;1278 vmetric = glyph.vmetric || defaultVMetrics;1279 vx = glyph.vmetric ? vmetric[1] : width * 0.5;1280 vx = -vx * widthAdvanceScale;1281 vy = vmetric[2] * widthAdvanceScale;1282 width = vmetric ? -vmetric[0] : width;1283 scaledX = vx / fontSizeScale;1284 scaledY = (x + vy) / fontSizeScale;1285 } else {1286 scaledX = x / fontSizeScale;1287 scaledY = 0;1288 }1289 if (font.remeasure && width > 0 && this.isFontSubpixelAAEnabled) {1290 // some standard fonts may not have the exact width, trying to1291 // rescale per character1292 var measuredWidth = ctx.measureText(character).width * 1000 /1293 fontSize * fontSizeScale;1294 var characterScaleX = width / measuredWidth;1295 restoreNeeded = true;1296 ctx.save();1297 ctx.scale(characterScaleX, 1);1298 scaledX /= characterScaleX;1299 }1300 if (simpleFillText && !accent) {1301 // common case1302 ctx.fillText(character, scaledX, scaledY);1303 } else {1304 this.paintChar(character, scaledX, scaledY);1305 if (accent) {1306 scaledAccentX = scaledX + accent.offset.x / fontSizeScale;1307 scaledAccentY = scaledY - accent.offset.y / fontSizeScale;1308 this.paintChar(accent.fontChar, scaledAccentX, scaledAccentY);1309 }1310 }1311 var charWidth = width * widthAdvanceScale + charSpacing * fontDirection;1312 x += charWidth;1313 if (restoreNeeded) {1314 ctx.restore();1315 }1316 }1317 if (vertical) {1318 current.y -= x * textHScale;1319 } else {1320 current.x += x * textHScale;1321 }1322 ctx.restore();1323 },1324 showType3Text: function CanvasGraphics_showType3Text(glyphs) {1325 // Type3 fonts - each glyph is a "mini-PDF"1326 var ctx = this.ctx;1327 var current = this.current;1328 var font = current.font;1329 var fontSize = current.fontSize;1330 var fontDirection = current.fontDirection;1331 var charSpacing = current.charSpacing;1332 var wordSpacing = current.wordSpacing;1333 var textHScale = current.textHScale * fontDirection;1334 var fontMatrix = current.fontMatrix || FONT_IDENTITY_MATRIX;1335 var glyphsLength = glyphs.length;1336 var isTextInvisible =1337 current.textRenderingMode === TextRenderingMode.INVISIBLE;1338 var i, glyph, width;1339 if (isTextInvisible || fontSize === 0) {1340 return;1341 }1342 ctx.save();1343 ctx.transform.apply(ctx, current.textMatrix);1344 ctx.translate(current.x, current.y);1345 ctx.scale(textHScale, fontDirection);1346 for (i = 0; i < glyphsLength; ++i) {1347 glyph = glyphs[i];1348 if (glyph === null) {1349 // word break1350 this.ctx.translate(wordSpacing, 0);1351 current.x += wordSpacing * textHScale;1352 continue;1353 } else if (isNum(glyph)) {1354 var spacingLength = -glyph * 0.001 * fontSize;1355 this.ctx.translate(spacingLength, 0);1356 current.x += spacingLength * textHScale;1357 continue;1358 }1359 var operatorList = font.charProcOperatorList[glyph.operatorListId];1360 if (!operatorList) {1361 warn('Type3 character \"' + glyph.operatorListId +1362 '\" is not available');1363 continue;1364 }1365 this.processingType3 = glyph;1366 this.save();1367 ctx.scale(fontSize, fontSize);1368 ctx.transform.apply(ctx, fontMatrix);1369 this.executeOperatorList(operatorList);1370 this.restore();1371 var transformed = Util.applyTransform([glyph.width, 0], fontMatrix);1372 width = transformed[0] * fontSize + charSpacing;1373 ctx.translate(width, 0);1374 current.x += width * textHScale;1375 }1376 ctx.restore();1377 this.processingType3 = null;1378 },1379 // Type3 fonts1380 setCharWidth: function CanvasGraphics_setCharWidth(xWidth, yWidth) {1381 // We can safely ignore this since the width should be the same1382 // as the width in the Widths array.1383 },1384 setCharWidthAndBounds: function CanvasGraphics_setCharWidthAndBounds(xWidth,1385 yWidth,1386 llx,1387 lly,1388 urx,1389 ury) {1390 // TODO According to the spec we're also suppose to ignore any operators1391 // that set color or include images while processing this type3 font.1392 this.ctx.rect(llx, lly, urx - llx, ury - lly);1393 this.clip();1394 this.endPath();1395 },1396 // Color1397 getColorN_Pattern: function CanvasGraphics_getColorN_Pattern(IR) {1398 var pattern;1399 if (IR[0] === 'TilingPattern') {1400 var color = IR[1];1401 pattern = new TilingPattern(IR, color, this.ctx, this.objs,1402 this.commonObjs, this.baseTransform);1403 } else {1404 pattern = getShadingPatternFromIR(IR);1405 }1406 return pattern;1407 },1408 setStrokeColorN: function CanvasGraphics_setStrokeColorN(/*...*/) {1409 this.current.strokeColor = this.getColorN_Pattern(arguments);1410 },1411 setFillColorN: function CanvasGraphics_setFillColorN(/*...*/) {1412 this.current.fillColor = this.getColorN_Pattern(arguments);1413 this.current.patternFill = true;1414 },1415 setStrokeRGBColor: function CanvasGraphics_setStrokeRGBColor(r, g, b) {1416 var color = Util.makeCssRgb(r, g, b);1417 this.ctx.strokeStyle = color;1418 this.current.strokeColor = color;1419 },1420 setFillRGBColor: function CanvasGraphics_setFillRGBColor(r, g, b) {1421 var color = Util.makeCssRgb(r, g, b);1422 this.ctx.fillStyle = color;1423 this.current.fillColor = color;1424 this.current.patternFill = false;1425 },1426 shadingFill: function CanvasGraphics_shadingFill(patternIR) {1427 var ctx = this.ctx;1428 this.save();1429 var pattern = getShadingPatternFromIR(patternIR);1430 ctx.fillStyle = pattern.getPattern(ctx, this, true);1431 var inv = ctx.mozCurrentTransformInverse;1432 if (inv) {1433 var canvas = ctx.canvas;1434 var width = canvas.width;1435 var height = canvas.height;1436 var bl = Util.applyTransform([0, 0], inv);1437 var br = Util.applyTransform([0, height], inv);1438 var ul = Util.applyTransform([width, 0], inv);1439 var ur = Util.applyTransform([width, height], inv);1440 var x0 = Math.min(bl[0], br[0], ul[0], ur[0]);1441 var y0 = Math.min(bl[1], br[1], ul[1], ur[1]);1442 var x1 = Math.max(bl[0], br[0], ul[0], ur[0]);1443 var y1 = Math.max(bl[1], br[1], ul[1], ur[1]);1444 this.ctx.fillRect(x0, y0, x1 - x0, y1 - y0);1445 } else {1446 // HACK to draw the gradient onto an infinite rectangle.1447 // PDF gradients are drawn across the entire image while1448 // Canvas only allows gradients to be drawn in a rectangle1449 // The following bug should allow us to remove this.1450 // https://bugzilla.mozilla.org/show_bug.cgi?id=6648841451 this.ctx.fillRect(-1e10, -1e10, 2e10, 2e10);1452 }1453 this.restore();1454 },1455 // Images1456 beginInlineImage: function CanvasGraphics_beginInlineImage() {1457 error('Should not call beginInlineImage');1458 },1459 beginImageData: function CanvasGraphics_beginImageData() {1460 error('Should not call beginImageData');1461 },1462 paintFormXObjectBegin: function CanvasGraphics_paintFormXObjectBegin(matrix,1463 bbox) {1464 this.save();1465 this.baseTransformStack.push(this.baseTransform);1466 if (isArray(matrix) && 6 === matrix.length) {1467 this.transform.apply(this, matrix);1468 }1469 this.baseTransform = this.ctx.mozCurrentTransform;1470 if (isArray(bbox) && 4 === bbox.length) {1471 var width = bbox[2] - bbox[0];1472 var height = bbox[3] - bbox[1];1473 this.ctx.rect(bbox[0], bbox[1], width, height);1474 this.clip();1475 this.endPath();1476 }1477 },1478 paintFormXObjectEnd: function CanvasGraphics_paintFormXObjectEnd() {1479 this.restore();1480 this.baseTransform = this.baseTransformStack.pop();1481 },1482 beginGroup: function CanvasGraphics_beginGroup(group) {1483 this.save();1484 var currentCtx = this.ctx;1485 // TODO non-isolated groups - according to Rik at adobe non-isolated1486 // group results aren't usually that different and they even have tools1487 // that ignore this setting. Notes from Rik on implmenting:1488 // - When you encounter an transparency group, create a new canvas with1489 // the dimensions of the bbox1490 // - copy the content from the previous canvas to the new canvas1491 // - draw as usual1492 // - remove the backdrop alpha:1493 // alphaNew = 1 - (1 - alpha)/(1 - alphaBackdrop) with 'alpha' the alpha1494 // value of your transparency group and 'alphaBackdrop' the alpha of the1495 // backdrop1496 // - remove background color:1497 // colorNew = color - alphaNew *colorBackdrop /(1 - alphaNew)1498 if (!group.isolated) {1499 info('TODO: Support non-isolated groups.');1500 }1501 // TODO knockout - supposedly possible with the clever use of compositing1502 // modes.1503 if (group.knockout) {1504 warn('Knockout groups not supported.');1505 }1506 var currentTransform = currentCtx.mozCurrentTransform;1507 if (group.matrix) {1508 currentCtx.transform.apply(currentCtx, group.matrix);1509 }1510 assert(group.bbox, 'Bounding box is required.');1511 // Based on the current transform figure out how big the bounding box1512 // will actually be.1513 var bounds = Util.getAxialAlignedBoundingBox(1514 group.bbox,1515 currentCtx.mozCurrentTransform);1516 // Clip the bounding box to the current canvas.1517 var canvasBounds = [0,1518 0,1519 currentCtx.canvas.width,1520 currentCtx.canvas.height];1521 bounds = Util.intersect(bounds, canvasBounds) || [0, 0, 0, 0];1522 // Use ceil in case we're between sizes so we don't create canvas that is1523 // too small and make the canvas at least 1x1 pixels.1524 var offsetX = Math.floor(bounds[0]);1525 var offsetY = Math.floor(bounds[1]);1526 var drawnWidth = Math.max(Math.ceil(bounds[2]) - offsetX, 1);1527 var drawnHeight = Math.max(Math.ceil(bounds[3]) - offsetY, 1);1528 var scaleX = 1, scaleY = 1;1529 if (drawnWidth > MAX_GROUP_SIZE) {1530 scaleX = drawnWidth / MAX_GROUP_SIZE;1531 drawnWidth = MAX_GROUP_SIZE;1532 }1533 if (drawnHeight > MAX_GROUP_SIZE) {1534 scaleY = drawnHeight / MAX_GROUP_SIZE;1535 drawnHeight = MAX_GROUP_SIZE;1536 }1537 var cacheId = 'groupAt' + this.groupLevel;1538 if (group.smask) {1539 // Using two cache entries is case if masks are used one after another.1540 cacheId += '_smask_' + ((this.smaskCounter++) % 2);1541 }1542 var scratchCanvas = CachedCanvases.getCanvas(1543 cacheId, drawnWidth, drawnHeight, true);1544 var groupCtx = scratchCanvas.context;1545 // Since we created a new canvas that is just the size of the bounding box1546 // we have to translate the group ctx.1547 groupCtx.scale(1 / scaleX, 1 / scaleY);1548 groupCtx.translate(-offsetX, -offsetY);1549 groupCtx.transform.apply(groupCtx, currentTransform);1550 if (group.smask) {1551 // Saving state and cached mask to be used in setGState.1552 this.smaskStack.push({1553 canvas: scratchCanvas.canvas,1554 context: groupCtx,1555 offsetX: offsetX,1556 offsetY: offsetY,1557 scaleX: scaleX,1558 scaleY: scaleY,1559 subtype: group.smask.subtype,1560 backdrop: group.smask.backdrop1561 });1562 } else {1563 // Setup the current ctx so when the group is popped we draw it at the1564 // right location.1565 currentCtx.setTransform(1, 0, 0, 1, 0, 0);1566 currentCtx.translate(offsetX, offsetY);1567 currentCtx.scale(scaleX, scaleY);1568 }1569 // The transparency group inherits all off the current graphics state1570 // except the blend mode, soft mask, and alpha constants.1571 copyCtxState(currentCtx, groupCtx);1572 this.ctx = groupCtx;1573 this.setGState([1574 ['BM', 'Normal'],1575 ['ca', 1],1576 ['CA', 1]1577 ]);1578 this.groupStack.push(currentCtx);1579 this.groupLevel++;1580 },1581 endGroup: function CanvasGraphics_endGroup(group) {1582 this.groupLevel--;1583 var groupCtx = this.ctx;1584 this.ctx = this.groupStack.pop();1585 // Turn off image smoothing to avoid sub pixel interpolation which can1586 // look kind of blurry for some pdfs.1587 if (this.ctx.imageSmoothingEnabled !== undefined) {1588 this.ctx.imageSmoothingEnabled = false;1589 } else {1590 this.ctx.mozImageSmoothingEnabled = false;1591 }1592 if (group.smask) {1593 this.tempSMask = this.smaskStack.pop();1594 } else {1595 this.ctx.drawImage(groupCtx.canvas, 0, 0);1596 }1597 this.restore();1598 },1599 beginAnnotations: function CanvasGraphics_beginAnnotations() {1600 this.save();1601 this.current = new CanvasExtraState();1602 // Odoo: fix issue with annotation position https://github.com/mozilla/pdf.js/pull/68141603 if (this.baseTransform) {1604 this.ctx.setTransform.apply(this.ctx, this.baseTransform);1605 }1606 },1607 endAnnotations: function CanvasGraphics_endAnnotations() {1608 this.restore();1609 },1610 beginAnnotation: function CanvasGraphics_beginAnnotation(rect, transform,1611 matrix) {1612 this.save();1613 if (isArray(rect) && 4 === rect.length) {1614 var width = rect[2] - rect[0];1615 var height = rect[3] - rect[1];1616 this.ctx.rect(rect[0], rect[1], width, height);1617 this.clip();1618 this.endPath();1619 }1620 this.transform.apply(this, transform);1621 this.transform.apply(this, matrix);1622 },1623 endAnnotation: function CanvasGraphics_endAnnotation() {1624 this.restore();1625 },1626 paintJpegXObject: function CanvasGraphics_paintJpegXObject(objId, w, h) {1627 var domImage = this.objs.get(objId);1628 if (!domImage) {1629 warn('Dependent image isn\'t ready yet');1630 return;1631 }1632 this.save();1633 var ctx = this.ctx;1634 // scale the image to the unit square1635 ctx.scale(1 / w, -1 / h);1636 ctx.drawImage(domImage, 0, 0, domImage.width, domImage.height,1637 0, -h, w, h);1638 if (this.imageLayer) {1639 var currentTransform = ctx.mozCurrentTransformInverse;1640 var position = this.getCanvasPosition(0, 0);1641 this.imageLayer.appendImage({1642 objId: objId,1643 left: position[0],1644 top: position[1],1645 width: w / currentTransform[0],1646 height: h / currentTransform[3]1647 });1648 }1649 this.restore();1650 },1651 paintImageMaskXObject: function CanvasGraphics_paintImageMaskXObject(img) {1652 var ctx = this.ctx;1653 var width = img.width, height = img.height;1654 var fillColor = this.current.fillColor;1655 var isPatternFill = this.current.patternFill;1656 var glyph = this.processingType3;1657 if (COMPILE_TYPE3_GLYPHS && glyph && glyph.compiled === undefined) {1658 if (width <= MAX_SIZE_TO_COMPILE && height <= MAX_SIZE_TO_COMPILE) {1659 glyph.compiled =1660 compileType3Glyph({data: img.data, width: width, height: height});1661 } else {1662 glyph.compiled = null;1663 }1664 }1665 if (glyph && glyph.compiled) {1666 glyph.compiled(ctx);1667 return;1668 }1669 var maskCanvas = CachedCanvases.getCanvas('maskCanvas', width, height);1670 var maskCtx = maskCanvas.context;1671 maskCtx.save();1672 putBinaryImageMask(maskCtx, img);1673 maskCtx.globalCompositeOperation = 'source-in';1674 maskCtx.fillStyle = isPatternFill ?...

Full Screen

Full Screen

Using AI Code Generation

copy

Full Screen

1var fs = require('fs');2var wptools = require('wptools');3var font = new wptools.Font();4font.importFont(fs.readFileSync('test.ttf'));5var glyph = font.compileType3Glyph(0x41, {x: 0, y: 0}, 1000, 1000);6var glyph2 = font.compileType3Glyph(0x42, {x: 0, y: 0}, 1000, 1000);7fs.writeFileSync('glyph.pdf', glyph);8fs.writeFileSync('glyph2.pdf', glyph2);

Full Screen

Using AI Code Generation

copy

Full Screen

1var wptextlayout = require('wptextlayout');2var font = new wptextlayout.Font();3font.loadSync('C:\\Windows\\Fonts\\arial.ttf');4var glyph = font.compileType3Glyph('A', 12);5var wptextlayout = require('wptextlayout');6var font = new wptextlayout.Font();7font.loadSync('C:\\Windows\\Fonts\\arial.ttf');8var glyph = font.compileType3Glyph('A', 12);

Full Screen

Using AI Code Generation

copy

Full Screen

1var fs = require('fs');2var path = require('path');3var fontFile = path.join(__dirname, 'fonts', 'Roboto-Regular.ttf');4var fontSize = 100;5var font = new wptools.Font(fontFile);6var glyph = font.getGlyph(glyphCode);7var glyphPath = glyph.compileType3Glyph(fontSize);8var svgPath = glyph.compileSVGPath(fontSize);9 + '</svg>\n';10fs.writeFileSync(path.join(__dirname, 'output', 'test.svg'), svg);11fs.writeFileSync(path.join(__dirname, 'output', 'test.glyph'), glyphPath);12console.log('done');

Full Screen

Using AI Code Generation

copy

Full Screen

1var wptools = require("wptools");2var fs = require("fs");3var path = require("path");4var font = new wptools.Font();5font.importFont("test.ttf");6var type3Glyph = font.compileType3Glyph({7 charStrings: {8 "a": {

Full Screen

Automation Testing Tutorials

Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.

LambdaTest Learning Hubs:

YouTube

You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.

Run wpt automation tests on LambdaTest cloud grid

Perform automation testing on 3000+ real desktop and mobile devices online.

Try LambdaTest Now !!

Get 100 minutes of automation test minutes FREE!!

Next-Gen App & Browser Testing Cloud

Was this article helpful?

Helpful

NotHelpful