vendor: 41,947 bytes, lines 1-1386
1// Copyright 2006 Google Inc. 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15 16// Known Issues: 17// 18// * Patterns only support repeat. 19// * Radial gradient are not implemented. The VML version of these look very 20// different from the canvas one. 21// * Clipping paths are not implemented. 22// * Coordsize. The width and height attribute have higher priority than the 23// width and height style values which isn't correct. 24// * Painting mode isn't implemented. 25// * Canvas width/height should is using content-box by default. IE in 26// Quirks mode will draw the canvas using border-box. Either change your 27// doctype to HTML5 28// (http://www.whatwg.org/specs/web-apps/current-work/#the-doctype) 29// or use Box Sizing Behavior from WebFX 30// (http://webfx.eae.net/dhtml/boxsizing/boxsizing.html) 31// * Non uniform scaling does not correctly scale strokes. 32// * Optimize. There is always room for speed improvements. 33 34// Only add this code if we do not already have a canvas implementation 35if (!document.createElement('canvas').getContext) { 36 37 (function() { 38 39 // alias some functions to make (compiled) code shorter 40 var m = Math; 41 var mr = m.round; 42 var ms = m.sin; 43 var mc = m.cos; 44 var abs = m.abs; 45 var sqrt = m.sqrt; 46 47 // this is used for sub pixel precision 48 var Z = 10; 49 var Z2 = Z / 2; 50 51 var IE_VERSION = +navigator.userAgent.match(/MSIE ([\d.]+)?/)[1]; 52 53 /** 54 * This funtion is assigned to the <canvas> elements as element.getContext(). 55 * @this {HTMLElement} 56 * @return {CanvasRenderingContext2D_} 57 */ 58 function getContext() { 59 return this.context_ || 60 (this.context_ = new CanvasRenderingContext2D_(this)); 61 } 62 63 var slice = Array.prototype.slice; 64 65 /** 66 * Binds a function to an object. The returned function will always use the 67 * passed in {@code obj} as {@code this}. 68 * 69 * Example: 70 * 71 * g = bind(f, obj, a, b) 72 * g(c, d) // will do f.call(obj, a, b, c, d) 73 * 74 * @param {Function} f The function to bind the object to 75 * @param {Object} obj The object that should act as this when the function 76 * is called 77 * @param {*} var_args Rest arguments that will be used as the initial 78 * arguments when the function is called 79 * @return {Function} A new function that has bound this 80 */ 81 function bind(f, obj, var_args) { 82 var a = slice.call(arguments, 2); 83 return function() { 84 return f.apply(obj, a.concat(slice.call(arguments))); 85 }; 86 } 87 88 function encodeHtmlAttribute(s) { 89 return String(s).replace(/&/g, '&').replace(/"/g, '"'); 90 } 91 92 function addNamespace(doc, prefix, urn) { 93 if (!doc.namespaces[prefix]) { 94 doc.namespaces.add(prefix, urn, '#default#VML'); 95 } 96 } 97 98 function addNamespacesAndStylesheet(doc) { 99 addNamespace(doc, 'g_vml_', 'urn:schemas-microsoft-com:vml'); 100 addNamespace(doc, 'g_o_', 'urn:schemas-microsoft-com:office:office'); 101 102 // Setup default CSS. Only add one style sheet per document 103 if (!doc.styleSheets['ex_canvas_']) { 104 var ss = doc.createStyleSheet(); 105 ss.owningElement.id = 'ex_canvas_'; 106 ss.cssText = 'canvas{display:inline-block;overflow:hidden;' + 107 // default size is 300x150 in Gecko and Opera 108 'text-align:left;width:300px;height:150px}'; 109 } 110 } 111 112 // Add namespaces and stylesheet at startup. 113 addNamespacesAndStylesheet(document); 114 115 var G_vmlCanvasManager_ = { 116 init: function(opt_doc) { 117 var doc = opt_doc || document; 118 // Create a dummy element so that IE will allow canvas elements to be 119 // recognized. 120 doc.createElement('canvas'); 121 doc.attachEvent('onreadystatechange', bind(this.init_, this, doc)); 122 }, 123 124 init_: function(doc) { 125 // find all canvas elements 126 var els = doc.getElementsByTagName('canvas'); 127 for (var i = 0; i < els.length; i++) { 128 this.initElement(els[i]); 129 } 130 }, 131 132 /** 133 * Public initializes a canvas element so that it can be used as canvas 134 * element from now on. This is called automatically before the page is 135 * loaded but if you are creating elements using createElement you need to 136 * make sure this is called on the element. 137 * @param {HTMLElement} el The canvas element to initialize. 138 * @return {HTMLElement} the element that was created. 139 */ 140 initElement: function(el) { 141 if (!el.getContext) { 142 el.getContext = getContext; 143 144 // Add namespaces and stylesheet to document of the element. 145 addNamespacesAndStylesheet(el.ownerDocument); 146 147 // Remove fallback content. There is no way to hide text nodes so we 148 // just remove all childNodes. We could hide all elements and remove 149 // text nodes but who really cares about the fallback content. 150 el.innerHTML = ''; 151 152 // do not use inline function because that will leak memory 153 el.attachEvent('onpropertychange', onPropertyChange); 154 el.attachEvent('onresize', onResize); 155 156 var attrs = el.attributes; 157 if (attrs.width && attrs.width.specified) { 158 // TODO: use runtimeStyle and coordsize 159 // el.getContext().setWidth_(attrs.width.nodeValue); 160 el.style.width = "100%"; 161 } else { 162 el.width = el.clientWidth; 163 } 164 if (attrs.height && attrs.height.specified) { 165 // TODO: use runtimeStyle and coordsize 166 // el.getContext().setHeight_(attrs.height.nodeValue); 167 el.style.height = "100%"; 168 } else { 169 el.height = el.clientHeight; 170 } 171 //el.getContext().setCoordsize_() 172 } 173 return el; 174 } 175 }; 176 177 function onPropertyChange(e) { 178 var el = e.srcElement; 179 180 switch (e.propertyName) { 181 case 'width': 182 el.getContext().clearRect(); 183 el.style.width = el.attributes.width.nodeValue + 'px'; 184 // In IE8 this does not trigger onresize. 185 el.firstChild.style.width = el.clientWidth + 'px'; 186 break; 187 case 'height': 188 el.getContext().clearRect(); 189 el.style.height = el.attributes.height.nodeValue + 'px'; 190 el.firstChild.style.height = el.clientHeight + 'px'; 191 break; 192 } 193 } 194 195 function onResize(e) { 196 var el = e.srcElement; 197 if (el.firstChild) { 198 el.firstChild.style.width = el.clientWidth + 'px'; 199 el.firstChild.style.height = el.clientHeight + 'px'; 200 } 201 } 202 203 G_vmlCanvasManager_.init(); 204 205 // precompute "00" to "FF" 206 var decToHex = []; 207 for (var i = 0; i < 16; i++) { 208 for (var j = 0; j < 16; j++) { 209 decToHex[i * 16 + j] = i.toString(16) + j.toString(16); 210 } 211 } 212 213 function createMatrixIdentity() { 214 return [ 215 [1, 0, 0], 216 [0, 1, 0], 217 [0, 0, 1] 218 ]; 219 } 220 221 function matrixMultiply(m1, m2) { 222 var result = createMatrixIdentity(); 223 224 for (var x = 0; x < 3; x++) { 225 for (var y = 0; y < 3; y++) { 226 var sum = 0; 227 228 for (var z = 0; z < 3; z++) { 229 sum += m1[x][z] * m2[z][y]; 230 } 231 232 result[x][y] = sum; 233 } 234 } 235 return result; 236 } 237 238 function copyState(o1, o2) { 239 o2.fillStyle = o1.fillStyle; 240 o2.lineCap = o1.lineCap; 241 o2.lineJoin = o1.lineJoin; 242 o2.lineWidth = o1.lineWidth; 243 o2.miterLimit = o1.miterLimit; 244 o2.shadowBlur = o1.shadowBlur; 245 o2.shadowColor = o1.shadowColor; 246 o2.shadowOffsetX = o1.shadowOffsetX; 247 o2.shadowOffsetY = o1.shadowOffsetY; 248 o2.strokeStyle = o1.strokeStyle; 249 o2.globalAlpha = o1.globalAlpha; 250 o2.font = o1.font; 251 o2.textAlign = o1.textAlign; 252 o2.textBaseline = o1.textBaseline; 253 o2.arcScaleX_ = o1.arcScaleX_; 254 o2.arcScaleY_ = o1.arcScaleY_; 255 o2.lineScale_ = o1.lineScale_; 256 } 257 258 var colorData = { 259 aliceblue: '#F0F8FF', 260 antiquewhite: '#FAEBD7', 261 aquamarine: '#7FFFD4', 262 azure: '#F0FFFF', 263 beige: '#F5F5DC', 264 bisque: '#FFE4C4', 265 black: '#000000', 266 blanchedalmond: '#FFEBCD', 267 blueviolet: '#8A2BE2', 268 brown: '#A52A2A', 269 burlywood: '#DEB887', 270 cadetblue: '#5F9EA0', 271 chartreuse: '#7FFF00', 272 chocolate: '#D2691E', 273 coral: '#FF7F50', 274 cornflowerblue: '#6495ED', 275 cornsilk: '#FFF8DC', 276 crimson: '#DC143C', 277 cyan: '#00FFFF', 278 darkblue: '#00008B', 279 darkcyan: '#008B8B', 280 darkgoldenrod: '#B8860B', 281 darkgray: '#A9A9A9', 282 darkgreen: '#006400', 283 darkgrey: '#A9A9A9', 284 darkkhaki: '#BDB76B', 285 darkmagenta: '#8B008B', 286 darkolivegreen: '#556B2F', 287 darkorange: '#FF8C00', 288 darkorchid: '#9932CC', 289 darkred: '#8B0000', 290 darksalmon: '#E9967A', 291 darkseagreen: '#8FBC8F', 292 darkslateblue: '#483D8B', 293 darkslategray: '#2F4F4F', 294 darkslategrey: '#2F4F4F', 295 darkturquoise: '#00CED1', 296 darkviolet: '#9400D3', 297 deeppink: '#FF1493', 298 deepskyblue: '#00BFFF', 299 dimgray: '#696969', 300 dimgrey: '#696969', 301 dodgerblue: '#1E90FF', 302 firebrick: '#B22222', 303 floralwhite: '#FFFAF0', 304 forestgreen: '#228B22', 305 gainsboro: '#DCDCDC', 306 ghostwhite: '#F8F8FF', 307 gold: '#FFD700', 308 goldenrod: '#DAA520', 309 grey: '#808080', 310 greenyellow: '#ADFF2F', 311 honeydew: '#F0FFF0', 312 hotpink: '#FF69B4', 313 indianred: '#CD5C5C', 314 indigo: '#4B0082', 315 ivory: '#FFFFF0', 316 khaki: '#F0E68C', 317 lavender: '#E6E6FA', 318 lavenderblush: '#FFF0F5', 319 lawngreen: '#7CFC00', 320 lemonchiffon: '#FFFACD', 321 lightblue: '#ADD8E6', 322 lightcoral: '#F08080', 323 lightcyan: '#E0FFFF', 324 lightgoldenrodyellow: '#FAFAD2', 325 lightgreen: '#90EE90', 326 lightgrey: '#D3D3D3', 327 lightpink: '#FFB6C1', 328 lightsalmon: '#FFA07A', 329 lightseagreen: '#20B2AA', 330 lightskyblue: '#87CEFA', 331 lightslategray: '#778899', 332 lightslategrey: '#778899', 333 lightsteelblue: '#B0C4DE', 334 lightyellow: '#FFFFE0', 335 limegreen: '#32CD32', 336 linen: '#FAF0E6', 337 magenta: '#FF00FF', 338 mediumaquamarine: '#66CDAA', 339 mediumblue: '#0000CD', 340 mediumorchid: '#BA55D3', 341 mediumpurple: '#9370DB', 342 mediumseagreen: '#3CB371', 343 mediumslateblue: '#7B68EE', 344 mediumspringgreen: '#00FA9A', 345 mediumturquoise: '#48D1CC', 346 mediumvioletred: '#C71585', 347 midnightblue: '#191970', 348 mintcream: '#F5FFFA', 349 mistyrose: '#FFE4E1', 350 moccasin: '#FFE4B5', 351 navajowhite: '#FFDEAD', 352 oldlace: '#FDF5E6', 353 olivedrab: '#6B8E23', 354 orange: '#FFA500', 355 orangered: '#FF4500', 356 orchid: '#DA70D6', 357 palegoldenrod: '#EEE8AA', 358 palegreen: '#98FB98', 359 paleturquoise: '#AFEEEE', 360 palevioletred: '#DB7093', 361 papayawhip: '#FFEFD5', 362 peachpuff: '#FFDAB9', 363 peru: '#CD853F', 364 pink: '#FFC0CB', 365 plum: '#DDA0DD', 366 powderblue: '#B0E0E6', 367 rosybrown: '#BC8F8F', 368 royalblue: '#4169E1', 369 saddlebrown: '#8B4513', 370 salmon: '#FA8072', 371 sandybrown: '#F4A460', 372 seagreen: '#2E8B57', 373 seashell: '#FFF5EE', 374 sienna: '#A0522D', 375 skyblue: '#87CEEB', 376 slateblue: '#6A5ACD', 377 slategray: '#708090', 378 slategrey: '#708090', 379 snow: '#FFFAFA', 380 springgreen: '#00FF7F', 381 steelblue: '#4682B4', 382 tan: '#D2B48C', 383 thistle: '#D8BFD8', 384 tomato: '#FF6347', 385 turquoise: '#40E0D0', 386 violet: '#EE82EE', 387 wheat: '#F5DEB3', 388 whitesmoke: '#F5F5F5', 389 yellowgreen: '#9ACD32' 390 }; 391 392 393 function getRgbHslContent(styleString) { 394 var start = styleString.indexOf('(', 3); 395 var end = styleString.indexOf(')', start + 1); 396 var parts = styleString.substring(start + 1, end).split(','); 397 // add alpha if needed 398 if (parts.length != 4 || styleString.charAt(3) != 'a') { 399 parts[3] = 1; 400 } 401 return parts; 402 } 403 404 function percent(s) { 405 return parseFloat(s) / 100; 406 } 407 408 function clamp(v, min, max) { 409 return Math.min(max, Math.max(min, v)); 410 } 411 412 function hslToRgb(parts){ 413 var r, g, b, h, s, l; 414 h = parseFloat(parts[0]) / 360 % 360; 415 if (h < 0) 416 h++; 417 s = clamp(percent(parts[1]), 0, 1); 418 l = clamp(percent(parts[2]), 0, 1); 419 if (s == 0) { 420 r = g = b = l; // achromatic 421 } else { 422 var q = l < 0.5 ? l * (1 + s) : l + s - l * s; 423 var p = 2 * l - q; 424 r = hueToRgb(p, q, h + 1 / 3); 425 g = hueToRgb(p, q, h); 426 b = hueToRgb(p, q, h - 1 / 3); 427 } 428 429 return '#' + decToHex[Math.floor(r * 255)] + 430 decToHex[Math.floor(g * 255)] + 431 decToHex[Math.floor(b * 255)]; 432 } 433 434 function hueToRgb(m1, m2, h) { 435 if (h < 0) 436 h++; 437 if (h > 1) 438 h--; 439 440 if (6 * h < 1) 441 return m1 + (m2 - m1) * 6 * h; 442 else if (2 * h < 1) 443 return m2; 444 else if (3 * h < 2) 445 return m1 + (m2 - m1) * (2 / 3 - h) * 6; 446 else 447 return m1; 448 } 449 450 var processStyleCache = {}; 451 452 function processStyle(styleString) { 453 if (styleString in processStyleCache) { 454 return processStyleCache[styleString]; 455 } 456 457 var str, alpha = 1; 458 459 styleString = String(styleString); 460 if (styleString.charAt(0) == '#') { 461 str = styleString; 462 } else if (/^rgb/.test(styleString)) { 463 var parts = getRgbHslContent(styleString); 464 var str = '#', n; 465 for (var i = 0; i < 3; i++) { 466 if (parts[i].indexOf('%') != -1) { 467 n = Math.floor(percent(parts[i]) * 255); 468 } else { 469 n = +parts[i]; 470 } 471 str += decToHex[clamp(n, 0, 255)]; 472 } 473 alpha = +parts[3]; 474 } else if (/^hsl/.test(styleString)) { 475 var parts = getRgbHslContent(styleString); 476 str = hslToRgb(parts); 477 alpha = parts[3]; 478 } else { 479 str = colorData[styleString] || styleString; 480 } 481 return processStyleCache[styleString] = {color: str, alpha: alpha}; 482 } 483 484 var DEFAULT_STYLE = { 485 style: 'normal', 486 variant: 'normal', 487 weight: 'normal', 488 size: 10, 489 family: 'sans-serif' 490 }; 491 492 // Internal text style cache 493 var fontStyleCache = {}; 494 495 function processFontStyle(styleString) { 496 if (fontStyleCache[styleString]) { 497 return fontStyleCache[styleString]; 498 } 499 500 var el = document.createElement('div'); 501 var style = el.style; 502 try { 503 style.font = styleString; 504 } catch (ex) { 505 // Ignore failures to set to invalid font. 506 } 507 508 return fontStyleCache[styleString] = { 509 style: style.fontStyle || DEFAULT_STYLE.style, 510 variant: style.fontVariant || DEFAULT_STYLE.variant, 511 weight: style.fontWeight || DEFAULT_STYLE.weight, 512 size: style.fontSize || DEFAULT_STYLE.size, 513 family: style.fontFamily || DEFAULT_STYLE.family 514 }; 515 } 516 517 function getComputedStyle(style, element) { 518 var computedStyle = {}; 519 520 for (var p in style) { 521 computedStyle[p] = style[p]; 522 } 523 524 // Compute the size 525 var canvasFontSize = parseFloat(element.currentStyle.fontSize), 526 fontSize = parseFloat(style.size); 527 528 if (typeof style.size == 'number') { 529 computedStyle.size = style.size; 530 } else if (style.size.indexOf('px') != -1) { 531 computedStyle.size = fontSize; 532 } else if (style.size.indexOf('em') != -1) { 533 computedStyle.size = canvasFontSize * fontSize; 534 } else if(style.size.indexOf('%') != -1) { 535 computedStyle.size = (canvasFontSize / 100) * fontSize; 536 } else if (style.size.indexOf('pt') != -1) { 537 computedStyle.size = fontSize / .75; 538 } else { 539 computedStyle.size = canvasFontSize; 540 } 541 542 // Different scaling between normal text and VML text. This was found using 543 // trial and error to get the same size as non VML text. 544 computedStyle.size *= 0.981; 545 546 return computedStyle; 547 } 548 549 function buildStyle(style) { 550 return style.style + ' ' + style.variant + ' ' + style.weight + ' ' + 551 style.size + 'px ' + style.family; 552 } 553 554 var lineCapMap = { 555 'butt': 'flat', 556 'round': 'round' 557 }; 558 559 function processLineCap(lineCap) { 560 return lineCapMap[lineCap] || 'square'; 561 } 562 563 /** 564 * This class implements CanvasRenderingContext2D interface as described by 565 * the WHATWG. 566 * @param {HTMLElement} canvasElement The element that the 2D context should 567 * be associated with 568 */ 569 function CanvasRenderingContext2D_(canvasElement) { 570 this.m_ = createMatrixIdentity(); 571 572 this.mStack_ = []; 573 this.aStack_ = []; 574 this.currentPath_ = []; 575 576 // Canvas context properties 577 this.strokeStyle = '#000'; 578 this.fillStyle = '#000'; 579 580 this.lineWidth = 1; 581 this.lineJoin = 'miter'; 582 this.lineCap = 'butt'; 583 this.miterLimit = Z * 1; 584 this.globalAlpha = 1; 585 this.font = '10px sans-serif'; 586 this.textAlign = 'left'; 587 this.textBaseline = 'alphabetic'; 588 this.canvas = canvasElement; 589 590 var cssText = 'width:' + canvasElement.clientWidth + 'px;height:' + 591 canvasElement.clientHeight + 'px;overflow:hidden;position:absolute'; 592 var el = canvasElement.ownerDocument.createElement('div'); 593 el.style.cssText = cssText; 594 canvasElement.appendChild(el); 595 596 var overlayEl = el.cloneNode(false); 597 // Use a non transparent background. 598 overlayEl.style.backgroundColor = 'red'; 599 overlayEl.style.filter = 'alpha(opacity=0)'; 600 canvasElement.appendChild(overlayEl); 601 602 this.element_ = el; 603 this.arcScaleX_ = 1; 604 this.arcScaleY_ = 1; 605 this.lineScale_ = 1; 606 } 607 608 var contextPrototype = CanvasRenderingContext2D_.prototype; 609 contextPrototype.clearRect = function() { 610 if (this.textMeasureEl_) { 611 this.textMeasureEl_.removeNode(true); 612 this.textMeasureEl_ = null; 613 } 614 this.element_.innerHTML = ''; 615 }; 616 617 contextPrototype.beginPath = function() { 618 // TODO: Branch current matrix so that save/restore has no effect 619 // as per safari docs. 620 this.currentPath_ = []; 621 }; 622 623 contextPrototype.moveTo = function(aX, aY) { 624 var p = getCoords(this, aX, aY); 625 this.currentPath_.push({type: 'moveTo', x: p.x, y: p.y}); 626 this.currentX_ = p.x; 627 this.currentY_ = p.y; 628 }; 629 630 contextPrototype.lineTo = function(aX, aY) { 631 var p = getCoords(this, aX, aY); 632 this.currentPath_.push({type: 'lineTo', x: p.x, y: p.y}); 633 634 this.currentX_ = p.x; 635 this.currentY_ = p.y; 636 }; 637 638 contextPrototype.bezierCurveTo = function(aCP1x, aCP1y, 639 aCP2x, aCP2y, 640 aX, aY) { 641 var p = getCoords(this, aX, aY); 642 var cp1 = getCoords(this, aCP1x, aCP1y); 643 var cp2 = getCoords(this, aCP2x, aCP2y); 644 bezierCurveTo(this, cp1, cp2, p); 645 }; 646 647 // Helper function that takes the already fixed cordinates. 648 function bezierCurveTo(self, cp1, cp2, p) { 649 self.currentPath_.push({ 650 type: 'bezierCurveTo', 651 cp1x: cp1.x, 652 cp1y: cp1.y, 653 cp2x: cp2.x, 654 cp2y: cp2.y, 655 x: p.x, 656 y: p.y 657 }); 658 self.currentX_ = p.x; 659 self.currentY_ = p.y; 660 } 661 662 contextPrototype.quadraticCurveTo = function(aCPx, aCPy, aX, aY) { 663 // the following is lifted almost directly from 664 // http://developer.mozilla.org/en/docs/Canvas_tutorial:Drawing_shapes 665 666 var cp = getCoords(this, aCPx, aCPy); 667 var p = getCoords(this, aX, aY); 668 669 var cp1 = { 670 x: this.currentX_ + 2.0 / 3.0 * (cp.x - this.currentX_), 671 y: this.currentY_ + 2.0 / 3.0 * (cp.y - this.currentY_) 672 }; 673 var cp2 = { 674 x: cp1.x + (p.x - this.currentX_) / 3.0, 675 y: cp1.y + (p.y - this.currentY_) / 3.0 676 }; 677 678 bezierCurveTo(this, cp1, cp2, p); 679 }; 680 681 contextPrototype.arc = function(aX, aY, aRadius, 682 aStartAngle, aEndAngle, aClockwise) { 683 aRadius *= Z; 684 var arcType = aClockwise ? 'at' : 'wa'; 685 686 var xStart = aX + mc(aStartAngle) * aRadius - Z2; 687 var yStart = aY + ms(aStartAngle) * aRadius - Z2; 688 689 var xEnd = aX + mc(aEndAngle) * aRadius - Z2; 690 var yEnd = aY + ms(aEndAngle) * aRadius - Z2; 691 692 // IE won't render arches drawn counter clockwise if xStart == xEnd. 693 if (xStart == xEnd && !aClockwise) { 694 xStart += 0.125; // Offset xStart by 1/80 of a pixel. Use something 695 // that can be represented in binary 696 } 697 698 var p = getCoords(this, aX, aY); 699 var pStart = getCoords(this, xStart, yStart); 700 var pEnd = getCoords(this, xEnd, yEnd); 701 702 this.currentPath_.push({type: arcType, 703 x: p.x, 704 y: p.y, 705 radius: aRadius, 706 xStart: pStart.x, 707 yStart: pStart.y, 708 xEnd: pEnd.x, 709 yEnd: pEnd.y}); 710 711 }; 712 713 contextPrototype.rect = function(aX, aY, aWidth, aHeight) { 714 this.moveTo(aX, aY); 715 this.lineTo(aX + aWidth, aY); 716 this.lineTo(aX + aWidth, aY + aHeight); 717 this.lineTo(aX, aY + aHeight); 718 this.closePath(); 719 }; 720 721 contextPrototype.strokeRect = function(aX, aY, aWidth, aHeight) { 722 var oldPath = this.currentPath_; 723 this.beginPath(); 724 725 this.moveTo(aX, aY); 726 this.lineTo(aX + aWidth, aY); 727 this.lineTo(aX + aWidth, aY + aHeight); 728 this.lineTo(aX, aY + aHeight); 729 this.closePath(); 730 this.stroke(); 731 732 this.currentPath_ = oldPath; 733 }; 734 735 contextPrototype.fillRect = function(aX, aY, aWidth, aHeight) { 736 var oldPath = this.currentPath_; 737 this.beginPath(); 738 739 this.moveTo(aX, aY); 740 this.lineTo(aX + aWidth, aY); 741 this.lineTo(aX + aWidth, aY + aHeight); 742 this.lineTo(aX, aY + aHeight); 743 this.closePath(); 744 this.fill(); 745 746 this.currentPath_ = oldPath; 747 }; 748 749 contextPrototype.createLinearGradient = function(aX0, aY0, aX1, aY1) { 750 var gradient = new CanvasGradient_('gradient'); 751 gradient.x0_ = aX0; 752 gradient.y0_ = aY0; 753 gradient.x1_ = aX1; 754 gradient.y1_ = aY1; 755 return gradient; 756 }; 757 758 contextPrototype.createRadialGradient = function(aX0, aY0, aR0, 759 aX1, aY1, aR1) { 760 var gradient = new CanvasGradient_('gradientradial'); 761 gradient.x0_ = aX0; 762 gradient.y0_ = aY0; 763 gradient.r0_ = aR0; 764 gradient.x1_ = aX1; 765 gradient.y1_ = aY1; 766 gradient.r1_ = aR1; 767 return gradient; 768 }; 769 770 contextPrototype.drawImage = function(image, var_args) { 771 var dx, dy, dw, dh, sx, sy, sw, sh; 772 773 // to find the original width we overide the width and height 774 var oldRuntimeWidth = image.runtimeStyle.width; 775 var oldRuntimeHeight = image.runtimeStyle.height; 776 image.runtimeStyle.width = 'auto'; 777 image.runtimeStyle.height = 'auto'; 778 779 // get the original size 780 var w = image.width; 781 var h = image.height; 782 783 // and remove overides 784 image.runtimeStyle.width = oldRuntimeWidth; 785 image.runtimeStyle.height = oldRuntimeHeight; 786 787 if (arguments.length == 3) { 788 dx = arguments[1]; 789 dy = arguments[2]; 790 sx = sy = 0; 791 sw = dw = w; 792 sh = dh = h; 793 } else if (arguments.length == 5) { 794 dx = arguments[1]; 795 dy = arguments[2]; 796 dw = arguments[3]; 797 dh = arguments[4]; 798 sx = sy = 0; 799 sw = w; 800 sh = h; 801 } else if (arguments.length == 9) { 802 sx = arguments[1]; 803 sy = arguments[2]; 804 sw = arguments[3]; 805 sh = arguments[4]; 806 dx = arguments[5]; 807 dy = arguments[6]; 808 dw = arguments[7]; 809 dh = arguments[8]; 810 } else { 811 throw Error('Invalid number of arguments'); 812 } 813 814 var d = getCoords(this, dx, dy); 815 816 var w2 = sw / 2; 817 var h2 = sh / 2; 818 819 var vmlStr = []; 820 821 var W = 10; 822 var H = 10; 823 824 // For some reason that I've now forgotten, using divs didn't work 825 vmlStr.push(' <g_vml_:group', 826 ' coordsize="', Z * W, ',', Z * H, '"', 827 ' coordorigin="0,0"' , 828 ' style="width:', W, 'px;height:', H, 'px;position:absolute;'); 829 830 // If filters are necessary (rotation exists), create them 831 // filters are bog-slow, so only create them if abbsolutely necessary 832 // The following check doesn't account for skews (which don't exist 833 // in the canvas spec (yet) anyway. 834 835 if (this.m_[0][0] != 1 || this.m_[0][1] || 836 this.m_[1][1] != 1 || this.m_[1][0]) { 837 var filter = []; 838 839 // Note the 12/21 reversal 840 filter.push('M11=', this.m_[0][0], ',', 841 'M12=', this.m_[1][0], ',', 842 'M21=', this.m_[0][1], ',', 843 'M22=', this.m_[1][1], ',', 844 'Dx=', mr(d.x / Z), ',', 845 'Dy=', mr(d.y / Z), ''); 846 847 // Bounding box calculation (need to minimize displayed area so that 848 // filters don't waste time on unused pixels. 849 var max = d; 850 var c2 = getCoords(this, dx + dw, dy); 851 var c3 = getCoords(this, dx, dy + dh); 852 var c4 = getCoords(this, dx + dw, dy + dh); 853 854 max.x = m.max(max.x, c2.x, c3.x, c4.x); 855 max.y = m.max(max.y, c2.y, c3.y, c4.y); 856 857 vmlStr.push('padding:0 ', mr(max.x / Z), 'px ', mr(max.y / Z), 858 'px 0;filter:progid:DXImageTransform.Microsoft.Matrix(', 859 filter.join(''), ", sizingmethod='clip');"); 860 861 } else { 862 vmlStr.push('top:', mr(d.y / Z), 'px;left:', mr(d.x / Z), 'px;'); 863 } 864 865 vmlStr.push(' ">' , 866 '<g_vml_:image src="', image.src, '"', 867 ' style="width:', Z * dw, 'px;', 868 ' height:', Z * dh, 'px"', 869 ' cropleft="', sx / w, '"', 870 ' croptop="', sy / h, '"', 871 ' cropright="', (w - sx - sw) / w, '"', 872 ' cropbottom="', (h - sy - sh) / h, '"', 873 ' />', 874 '</g_vml_:group>'); 875 876 this.element_.insertAdjacentHTML('BeforeEnd', vmlStr.join('')); 877 }; 878 879 contextPrototype.stroke = function(aFill) { 880 var lineStr = []; 881 var lineOpen = false; 882 883 var W = 10; 884 var H = 10; 885 886 lineStr.push('<g_vml_:shape', 887 ' filled="', !!aFill, '"', 888 ' style="position:absolute;width:', W, 'px;height:', H, 'px;"', 889 ' coordorigin="0,0"', 890 ' coordsize="', Z * W, ',', Z * H, '"', 891 ' stroked="', !aFill, '"', 892 ' path="'); 893 894 var newSeq = false; 895 var min = {x: null, y: null}; 896 var max = {x: null, y: null}; 897 898 for (var i = 0; i < this.currentPath_.length; i++) { 899 var p = this.currentPath_[i]; 900 var c; 901 902 switch (p.type) { 903 case 'moveTo': 904 c = p; 905 lineStr.push(' m ', mr(p.x), ',', mr(p.y)); 906 break; 907 case 'lineTo': 908 lineStr.push(' l ', mr(p.x), ',', mr(p.y)); 909 break; 910 case 'close': 911 lineStr.push(' x '); 912 p = null; 913 break; 914 case 'bezierCurveTo': 915 lineStr.push(' c ', 916 mr(p.cp1x), ',', mr(p.cp1y), ',', 917 mr(p.cp2x), ',', mr(p.cp2y), ',', 918 mr(p.x), ',', mr(p.y)); 919 break; 920 case 'at': 921 case 'wa': 922 lineStr.push(' ', p.type, ' ', 923 mr(p.x - this.arcScaleX_ * p.radius), ',', 924 mr(p.y - this.arcScaleY_ * p.radius), ' ', 925 mr(p.x + this.arcScaleX_ * p.radius), ',', 926 mr(p.y + this.arcScaleY_ * p.radius), ' ', 927 mr(p.xStart), ',', mr(p.yStart), ' ', 928 mr(p.xEnd), ',', mr(p.yEnd)); 929 break; 930 } 931 932 933 // TODO: Following is broken for curves due to 934 // move to proper paths. 935 936 // Figure out dimensions so we can do gradient fills 937 // properly 938 if (p) { 939 if (min.x == null || p.x < min.x) { 940 min.x = p.x; 941 } 942 if (max.x == null || p.x > max.x) { 943 max.x = p.x; 944 } 945 if (min.y == null || p.y < min.y) { 946 min.y = p.y; 947 } 948 if (max.y == null || p.y > max.y) { 949 max.y = p.y; 950 } 951 } 952 } 953 lineStr.push(' ">'); 954 955 if (!aFill) { 956 appendStroke(this, lineStr); 957 } else { 958 appendFill(this, lineStr, min, max); 959 } 960 961 lineStr.push('</g_vml_:shape>'); 962 963 this.element_.insertAdjacentHTML('beforeEnd', lineStr.join('')); 964 }; 965 966 function appendStroke(ctx, lineStr) { 967 var a = processStyle(ctx.strokeStyle); 968 var color = a.color; 969 var opacity = a.alpha * ctx.globalAlpha; 970 var lineWidth = ctx.lineScale_ * ctx.lineWidth; 971 972 // VML cannot correctly render a line if the width is less than 1px. 973 // In that case, we dilute the color to make the line look thinner. 974 if (lineWidth < 1) { 975 opacity *= lineWidth; 976 } 977 978 lineStr.push( 979 '<g_vml_:stroke', 980 ' opacity="', opacity, '"', 981 ' joinstyle="', ctx.lineJoin, '"', 982 ' miterlimit="', ctx.miterLimit, '"', 983 ' endcap="', processLineCap(ctx.lineCap), '"', 984 ' weight="', lineWidth, 'px"', 985 ' color="', color, '" />' 986 ); 987 } 988 989 function appendFill(ctx, lineStr, min, max) { 990 var fillStyle = ctx.fillStyle; 991 var arcScaleX = ctx.arcScaleX_; 992 var arcScaleY = ctx.arcScaleY_; 993 var width = max.x - min.x; 994 var height = max.y - min.y; 995 if (fillStyle instanceof CanvasGradient_) { 996 // TODO: Gradients transformed with the transformation matrix. 997 var angle = 0; 998 var focus = {x: 0, y: 0}; 999 1000 // additional offset 1001 var shift = 0; 1002 // scale factor for offset 1003 var expansion = 1; 1004 1005 if (fillStyle.type_ == 'gradient') { 1006 var x0 = fillStyle.x0_ / arcScaleX; 1007 var y0 = fillStyle.y0_ / arcScaleY; 1008 var x1 = fillStyle.x1_ / arcScaleX; 1009 var y1 = fillStyle.y1_ / arcScaleY; 1010 var p0 = getCoords(ctx, x0, y0); 1011 var p1 = getCoords(ctx, x1, y1); 1012 var dx = p1.x - p0.x; 1013 var dy = p1.y - p0.y; 1014 angle = Math.atan2(dx, dy) * 180 / Math.PI; 1015 1016 // The angle should be a non-negative number. 1017 if (angle < 0) { 1018 angle += 360; 1019 } 1020 1021 // Very small angles produce an unexpected result because they are 1022 // converted to a scientific notation string. 1023 if (angle < 1e-6) { 1024 angle = 0; 1025 } 1026 } else { 1027 var p0 = getCoords(ctx, fillStyle.x0_, fillStyle.y0_); 1028 focus = { 1029 x: (p0.x - min.x) / width, 1030 y: (p0.y - min.y) / height 1031 }; 1032 1033 width /= arcScaleX * Z; 1034 height /= arcScaleY * Z; 1035 var dimension = m.max(width, height); 1036 shift = 2 * fillStyle.r0_ / dimension; 1037 expansion = 2 * fillStyle.r1_ / dimension - shift; 1038 } 1039 1040 // We need to sort the color stops in ascending order by offset, 1041 // otherwise IE won't interpret it correctly. 1042 var stops = fillStyle.colors_; 1043 stops.sort(function(cs1, cs2) { 1044 return cs1.offset - cs2.offset; 1045 }); 1046 1047 var length = stops.length; 1048 var color1 = stops[0].color; 1049 var color2 = stops[length - 1].color; 1050 var opacity1 = stops[0].alpha * ctx.globalAlpha; 1051 var opacity2 = stops[length - 1].alpha * ctx.globalAlpha; 1052 1053 var colors = []; 1054 for (var i = 0; i < length; i++) { 1055 var stop = stops[i]; 1056 colors.push(stop.offset * expansion + shift + ' ' + stop.color); 1057 } 1058 1059 // When colors attribute is used, the meanings of opacity and o:opacity2 1060 // are reversed. 1061 lineStr.push('<g_vml_:fill type="', fillStyle.type_, '"', 1062 ' method="none" focus="100%"', 1063 ' color="', color1, '"', 1064 ' color2="', color2, '"', 1065 ' colors="', colors.join(','), '"', 1066 ' opacity="', opacity2, '"', 1067 ' g_o_:opacity2="', opacity1, '"', 1068 ' angle="', angle, '"', 1069 ' focusposition="', focus.x, ',', focus.y, '" />'); 1070 } else if (fillStyle instanceof CanvasPattern_) { 1071 if (width && height) { 1072 var deltaLeft = -min.x; 1073 var deltaTop = -min.y; 1074 lineStr.push('<g_vml_:fill', 1075 ' position="', 1076 deltaLeft / width * arcScaleX * arcScaleX, ',', 1077 deltaTop / height * arcScaleY * arcScaleY, '"', 1078 ' type="tile"', 1079 // TODO: Figure out the correct size to fit the scale. 1080 //' size="', w, 'px ', h, 'px"', 1081 ' src="', fillStyle.src_, '" />'); 1082 } 1083 } else { 1084 var a = processStyle(ctx.fillStyle); 1085 var color = a.color; 1086 var opacity = a.alpha * ctx.globalAlpha; 1087 lineStr.push('<g_vml_:fill color="', color, '" opacity="', opacity, 1088 '" />'); 1089 } 1090 } 1091 1092 contextPrototype.fill = function() { 1093 this.stroke(true); 1094 }; 1095 1096 contextPrototype.closePath = function() { 1097 this.currentPath_.push({type: 'close'}); 1098 }; 1099 1100 function getCoords(ctx, aX, aY) { 1101 var m = ctx.m_; 1102 return { 1103 x: Z * (aX * m[0][0] + aY * m[1][0] + m[2][0]) - Z2, 1104 y: Z * (aX * m[0][1] + aY * m[1][1] + m[2][1]) - Z2 1105 }; 1106 }; 1107 1108 contextPrototype.save = function() { 1109 var o = {}; 1110 copyState(this, o); 1111 this.aStack_.push(o); 1112 this.mStack_.push(this.m_); 1113 this.m_ = matrixMultiply(createMatrixIdentity(), this.m_); 1114 }; 1115 1116 contextPrototype.restore = function() { 1117 if (this.aStack_.length) { 1118 copyState(this.aStack_.pop(), this); 1119 this.m_ = this.mStack_.pop(); 1120 } 1121 }; 1122 1123 function matrixIsFinite(m) { 1124 return isFinite(m[0][0]) && isFinite(m[0][1]) && 1125 isFinite(m[1][0]) && isFinite(m[1][1]) && 1126 isFinite(m[2][0]) && isFinite(m[2][1]); 1127 } 1128 1129 function setM(ctx, m, updateLineScale) { 1130 if (!matrixIsFinite(m)) { 1131 return; 1132 } 1133 ctx.m_ = m; 1134 1135 if (updateLineScale) { 1136 // Get the line scale. 1137 // Determinant of this.m_ means how much the area is enlarged by the 1138 // transformation. So its square root can be used as a scale factor 1139 // for width. 1140 var det = m[0][0] * m[1][1] - m[0][1] * m[1][0]; 1141 ctx.lineScale_ = sqrt(abs(det)); 1142 } 1143 } 1144 1145 contextPrototype.translate = function(aX, aY) { 1146 var m1 = [ 1147 [1, 0, 0], 1148 [0, 1, 0], 1149 [aX, aY, 1] 1150 ]; 1151 1152 setM(this, matrixMultiply(m1, this.m_), false); 1153 }; 1154 1155 contextPrototype.rotate = function(aRot) { 1156 var c = mc(aRot); 1157 var s = ms(aRot); 1158 1159 var m1 = [ 1160 [c, s, 0], 1161 [-s, c, 0], 1162 [0, 0, 1] 1163 ]; 1164 1165 setM(this, matrixMultiply(m1, this.m_), false); 1166 }; 1167 1168 contextPrototype.scale = function(aX, aY) { 1169 this.arcScaleX_ *= aX; 1170 this.arcScaleY_ *= aY; 1171 var m1 = [ 1172 [aX, 0, 0], 1173 [0, aY, 0], 1174 [0, 0, 1] 1175 ]; 1176 1177 setM(this, matrixMultiply(m1, this.m_), true); 1178 }; 1179 1180 contextPrototype.transform = function(m11, m12, m21, m22, dx, dy) { 1181 var m1 = [ 1182 [m11, m12, 0], 1183 [m21, m22, 0], 1184 [dx, dy, 1] 1185 ]; 1186 1187 setM(this, matrixMultiply(m1, this.m_), true); 1188 }; 1189 1190 contextPrototype.setTransform = function(m11, m12, m21, m22, dx, dy) { 1191 var m = [ 1192 [m11, m12, 0], 1193 [m21, m22, 0], 1194 [dx, dy, 1] 1195 ]; 1196 1197 setM(this, m, true); 1198 }; 1199 1200 /** 1201 * The text drawing function. 1202 * The maxWidth argument isn't taken in account, since no browser supports 1203 * it yet. 1204 */ 1205 contextPrototype.drawText_ = function(text, x, y, maxWidth, stroke) { 1206 var m = this.m_, 1207 delta = 1000, 1208 left = 0, 1209 right = delta, 1210 offset = {x: 0, y: 0}, 1211 lineStr = []; 1212 1213 var fontStyle = getComputedStyle(processFontStyle(this.font), 1214 this.element_); 1215 1216 var fontStyleString = buildStyle(fontStyle); 1217 1218 var elementStyle = this.element_.currentStyle; 1219 var textAlign = this.textAlign.toLowerCase(); 1220 switch (textAlign) { 1221 case 'left': 1222 case 'center': 1223 case 'right': 1224 break; 1225 case 'end': 1226 textAlign = elementStyle.direction == 'ltr' ? 'right' : 'left'; 1227 break; 1228 case 'start': 1229 textAlign = elementStyle.direction == 'rtl' ? 'right' : 'left'; 1230 break; 1231 default: 1232 textAlign = 'left'; 1233 } 1234 1235 // 1.75 is an arbitrary number, as there is no info about the text baseline 1236 switch (this.textBaseline) { 1237 case 'hanging': 1238 case 'top': 1239 offset.y = fontStyle.size / 1.75; 1240 break; 1241 case 'middle': 1242 break; 1243 default: 1244 case null: 1245 case 'alphabetic': 1246 case 'ideographic': 1247 case 'bottom': 1248 offset.y = -fontStyle.size / 2.25; 1249 break; 1250 } 1251 1252 switch(textAlign) { 1253 case 'right': 1254 left = delta; 1255 right = 0.05; 1256 break; 1257 case 'center': 1258 left = right = delta / 2; 1259 break; 1260 } 1261 1262 var d = getCoords(this, x + offset.x, y + offset.y); 1263 1264 lineStr.push('<g_vml_:line from="', -left ,' 0" to="', right ,' 0.05" ', 1265 ' coordsize="100 100" coordorigin="0 0"', 1266 ' filled="', !stroke, '" stroked="', !!stroke, 1267 '" style="position:absolute;width:1px;height:1px;">'); 1268 1269 if (stroke) { 1270 appendStroke(this, lineStr); 1271 } else { 1272 // TODO: Fix the min and max params. 1273 appendFill(this, lineStr, {x: -left, y: 0}, 1274 {x: right, y: fontStyle.size}); 1275 } 1276 1277 var skewM = m[0][0].toFixed(3) + ',' + m[1][0].toFixed(3) + ',' + 1278 m[0][1].toFixed(3) + ',' + m[1][1].toFixed(3) + ',0,0'; 1279 1280 var skewOffset = mr(d.x / Z) + ',' + mr(d.y / Z); 1281 1282 lineStr.push('<g_vml_:skew on="t" matrix="', skewM ,'" ', 1283 ' offset="', skewOffset, '" origin="', left ,' 0" />', 1284 '<g_vml_:path textpathok="true" />', 1285 '<g_vml_:textpath on="true" string="', 1286 encodeHtmlAttribute(text), 1287 '" style="v-text-align:', textAlign, 1288 ';font:', encodeHtmlAttribute(fontStyleString), 1289 '" /></g_vml_:line>'); 1290 1291 this.element_.insertAdjacentHTML('beforeEnd', lineStr.join('')); 1292 }; 1293 1294 contextPrototype.fillText = function(text, x, y, maxWidth) { 1295 this.drawText_(text, x, y, maxWidth, false); 1296 }; 1297 1298 contextPrototype.strokeText = function(text, x, y, maxWidth) { 1299 this.drawText_(text, x, y, maxWidth, true); 1300 }; 1301 1302 contextPrototype.measureText = function(text) { 1303 if (!this.textMeasureEl_) { 1304 var s = '<span style="position:absolute;' + 1305 'top:-20000px;left:0;padding:0;margin:0;border:none;' + 1306 'white-space:pre;"></span>'; 1307 this.element_.insertAdjacentHTML('beforeEnd', s); 1308 this.textMeasureEl_ = this.element_.lastChild; 1309 } 1310 var doc = this.element_.ownerDocument; 1311 this.textMeasureEl_.innerHTML = ''; 1312 this.textMeasureEl_.style.font = this.font; 1313 // Don't use innerHTML or innerText because they allow markup/whitespace. 1314 this.textMeasureEl_.appendChild(doc.createTextNode(text)); 1315 return {width: this.textMeasureEl_.offsetWidth}; 1316 }; 1317 1318 /******** STUBS ********/ 1319 contextPrototype.clip = function() { 1320 // TODO: Implement 1321 }; 1322 1323 contextPrototype.arcTo = function() { 1324 // TODO: Implement 1325 }; 1326 1327 contextPrototype.createPattern = function(image, repetition) { 1328 return new CanvasPattern_(image, repetition); 1329 }; 1330 1331 // Gradient / Pattern Stubs 1332 function CanvasGradient_(aType) { 1333 this.type_ = aType; 1334 this.x0_ = 0; 1335 this.y0_ = 0; 1336 this.r0_ = 0; 1337 this.x1_ = 0; 1338 this.y1_ = 0; 1339 this.r1_ = 0; 1340 this.colors_ = []; 1341 } 1342 1343 CanvasGradient_.prototype.addColorStop = function(aOffset, aColor) { 1344 aColor = processStyle(aColor); 1345 this.colors_.push({offset: aOffset, 1346 color: aColor.color, 1347 alpha: aColor.alpha}); 1348 }; 1349 1350 function CanvasPattern_(image, repetition) { 1351 assertImageIsValid(image); 1352 switch (repetition) { 1353 case 'repeat': 1354 case null: 1355 case '': 1356 this.repetition_ = 'repeat'; 1357 break 1358 case 'repeat-x': 1359 case 'repeat-y': 1360 case 'no-repeat': 1361 this.repetition_ = repetition; 1362 break; 1363 default: 1364 throwException('SYNTAX_ERR'); 1365 } 1366 1367 this.src_ = image.src; 1368 this.width_ = image.width; 1369 this.height_ = image.height; 1370 } 1371 1372 function throwException(s) { 1373 throw new DOMException_(s); 1374 } 1375 1376 function assertImageIsValid(img) { 1377 if (!img || img.nodeType != 1 || img.tagName != 'IMG') { 1378 throwException('TYPE_MISMATCH_ERR'); 1379 } 1380 if (img.readyState != 'complete') { 1381 throwException('INVALID_STATE_ERR'); 1382 } 1383 } 1384 1385 function DOMException_(s) { 1386 this.code = this[s];
1387 this.message = s +': DOM Exception ' + this.code; 1388 } 1389 var p = DOMException_.prototype = new Error; 1390 p.INDEX_SIZE_ERR = 1; 1391 p.DOMSTRING_SIZE_ERR = 2; 1392 p.HIERARCHY_REQUEST_ERR = 3; 1393 p.WRONG_DOCUMENT_ERR = 4; 1394 p.INVALID_CHARACTER_ERR = 5; 1395 p.NO_DATA_ALLOWED_ERR = 6; 1396 p.NO_MODIFICATION_ALLOWED_ERR = 7; 1397 p.NOT_FOUND_ERR = 8; 1398 p.NOT_SUPPORTED_ERR = 9; 1399 p.INUSE_ATTRIBUTE_ERR = 10; 1400 p.INVALID_STATE_ERR = 11; 1401 p.SYNTAX_ERR = 12; 1402 p.INVALID_MODIFICATION_ERR = 13; 1403 p.NAMESPACE_ERR = 14; 1404 p.INVALID_ACCESS_ERR = 15; 1405 p.VALIDATION_ERR = 16; 1406 p.TYPE_MISMATCH_ERR = 17; 1407 1408 // set up externs 1409 G_vmlCanvasManager = G_vmlCanvasManager_; 1410 CanvasRenderingContext2D = CanvasRenderingContext2D_; 1411 CanvasGradient = CanvasGradient_; 1412 CanvasPattern = CanvasPattern_; 1413 DOMException = DOMException_; 1414 })(); 1415 1416} // if
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.