def __init__(self): try: ns = doc().namespaces.item("v") except: doc().namespaces.add("v", "urn:schemas-microsoft-com:vml") doc().createStyleSheet( ).cssText = "v\\:*{behavior:url(#default#VML);}" """* * This will be used for an array join. Currently a bit faster than * StringBuilder.append() & toString() because of the extra collections * overhead. """ self.pathStr = JSOStack() """* * Stack uses preallocated arrays which makes push() slightly faster than * [].push() since each push is simply an indexed setter. """ self.contextStack = [] self.currentX = 0 self.currentY = 0 self.parentElement = None self.parentHeight = 0 self.parentWidth = 0
def __init__(self): try: ns = doc().namespaces.item("v") except: doc().namespaces.add("v", "urn:schemas-microsoft-com:vml") doc().createStyleSheet().cssText = "v\\:*{behavior:url(#default#VML);}" """* * This will be used for an array join. Currently a bit faster than * StringBuilder.append() & toString() because of the extra collections * overhead. """ self.pathStr = JSOStack() """* * Stack uses preallocated arrays which makes push() slightly faster than * [].push() since each push is simply an indexed setter. """ self.contextStack = [] self.currentX = 0 self.currentY = 0 self.parentElement = None self.parentHeight = 0 self.parentWidth = 0
class GWTCanvasImplIE6: def __init__(self): try: ns = doc().namespaces.item("v") except: doc().namespaces.add("v", "urn:schemas-microsoft-com:vml") doc().createStyleSheet().cssText = "v\\:*{behavior:url(#default#VML);}" """* * This will be used for an array join. Currently a bit faster than * StringBuilder.append() & toString() because of the extra collections * overhead. """ self.pathStr = JSOStack() """* * Stack uses preallocated arrays which makes push() slightly faster than * [].push() since each push is simply an indexed setter. """ self.contextStack = [] self.currentX = 0 self.currentY = 0 self.parentElement = None self.parentHeight = 0 self.parentWidth = 0 def arc(self, x, y, radius, startAngle, endAngle, anticlockwise): self.pathStr.append(PathElement.arc(x, y, radius, startAngle, endAngle, anticlockwise, self)) def beginPath(self): self.pathStr.clear() def clear(self, width=0, height=0): self.pathStr.clear() DOM.setInnerHTML(self.parentElement, "") def closePath(self): self.pathStr.append(PathElement.closePath()) def createElement(self): self.context = VMLContext() self.matrix = self.context.matrix return self.createParentElement() def createParentElement(self): self.parentElement = DOM.createElement("div") DOM.setStyleAttribute(self.parentElement, "overflow", "hidden") return self.parentElement def setFont(self, font): pass # NOT IMPLEMENTED def cubicCurveTo(self, cp1x, cp1y, cp2x, cp2y, x, y): self.pathStr.append(PathElement.bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y, self)) self.currentX = x self.currentY = y def drawImage(self, img, *args): if isinstance(img, Widget): img = img.getElement() fullWidth = img.width fullHeight = img.height if len(args) == 8: sourceX = args[0] sourceY = args[1] sourceWidth = args[2] sourceHeight = args[3] destX = args[4] destY = args[5] destWidth = args[6] destHeight = args[7] elif len(args) == 4: sourceX = 0 sourceY = 0 sourceWidth = fullWidth sourceHeight = fullHeight destX = args[0] destY = args[1] destWidth = args[2] destHeight = args[3] elif len(args) == 2: sourceX = 0 sourceY = 0 sourceWidth = fullWidth sourceHeight = fullHeight destX = args[0] destY = args[1] destWidth = fullWidth destHeight = fullHeight vmlStr = [] # JSOStack.getScratchArray() vmlStr.append("<v:group style=\"position:absolute;width:10;height:10;") dX = self.getCoordX(self.matrix, destX, destY) dY = self.getCoordY(self.matrix, destX, destY) # If we have a transformation matrix with rotation/scale, we # apply a filter if self.context.matrix[0] != 1 or self.context.matrix[1] != 0: # We create a padding bounding box to prevent clipping. vmlStr.append("padding-right:") vmlStr.append(str(self.parentWidth) + "px;") vmlStr.append("padding-bottom:") vmlStr.append(str(self.parentHeight) + "px;") vmlStr.append("filter:progid:DXImageTransform.Microsoft.Matrix(M11='") vmlStr.append("" + str(self.matrix[0])) vmlStr.append("',") vmlStr.append("M12='") vmlStr.append("" + str(self.matrix[1])) vmlStr.append("',") vmlStr.append("M21='") vmlStr.append(str(self.matrix[3])) vmlStr.append("',") vmlStr.append("M22='") vmlStr.append(str(self.matrix[4])) vmlStr.append("',") vmlStr.append("Dx='") vmlStr.append(str(math.floor(((dX / 10))))) vmlStr.append("',") vmlStr.append("Dy='") vmlStr.append(str(math.floor(((dY / 10))))) vmlStr.append("', SizingMethod='clip');") else: vmlStr.append("left:") vmlStr.append("%dpx;" % int(dX / 10)) vmlStr.append("top:") vmlStr.append("%dpx" % int(dY / 10)) vmlStr.append("\" coordsize=\"100,100\" coordorigin=\"0,0\"><v:image src=\"") vmlStr.append(DOM.getAttribute(img, "src")) vmlStr.append("\" style=\"") vmlStr.append("width:") vmlStr.append(str(int(destWidth * 10))) vmlStr.append(";height:") vmlStr.append(str(int(destHeight * 10))) vmlStr.append(";\" cropleft=\"") vmlStr.append(str(sourceX / fullWidth)) vmlStr.append("\" croptop=\"") vmlStr.append(str(sourceY / fullHeight)) vmlStr.append("\" cropright=\"") vmlStr.append(str((fullWidth - sourceX - sourceWidth) / fullWidth)) vmlStr.append("\" cropbottom=\"") vmlStr.append(str((fullHeight - sourceY - sourceHeight) / fullHeight)) vmlStr.append("\"/></v:group>") self.insert("BeforeEnd", ''.join(vmlStr)) def appendGradient(self, style, shapeStr): colorStops = style.gradient.colorStops length = len(colorStops) shapeStr.append("\" color=\"") shapeStr.append(str(colorStops[0].color)) shapeStr.append("\" color2=\"") shapeStr.append(str(colorStops[length - 1].color)) shapeStr.append("\" type=\"") shapeStr.append(style.gradient.type) if style.gradient.type == 'gradient': #Window.alert(" gdx: " + str(style.gradient.dx) + # " gdy: " + str(style.gradient.dy) + # " gl: " + str(style.gradient.length) + # " ga: " + str(style.gradient.angle)) # Now add all the color stops colors = "" for i in range(1, len(colorStops)): cs = colorStops[i] #Window.alert("color stop offset: " + str(cs.offset)) stopPosn = cs.offset colors += "%d%%" % (int(stopPosn * 100 )) colors += str(cs.color) + "," shapeStr.append("\" colors=\"") shapeStr.append(colors) else: """ gradientradial under VML is limited to rectangular gradients see http://msdn.microsoft.com/en-us/library/bb264135%28v=vs.85%29.aspx so while this code is here, the results will never be what the rest of the world would expect - go figure """ minX = self.pathStr.getMinCoordX() maxX = self.pathStr.getMaxCoordX() minY = self.pathStr.getMinCoordY() maxY = self.pathStr.getMaxCoordY() dx = maxX - minX dy = maxY - minY fillLength = math.sqrt((dx * dx) + (dy * dy)) #Window.alert("fillLength: " + str(fillLength) + # " gdx: " + str(style.gradient.dx) + # " gdy: " + str(style.gradient.dy) + # " gl: " + str(style.gradient.length) + # " ga: " + str(style.gradient.angle) + # " gsr: " + str(style.gradient.startRad) + # " ger: " + str(style.gradient.endRad)) # need some proper math to calculate the focus position focusX = 50 focusY = 50 # Now add all the color stops colors = "" for i in range(1, len(colorStops)): cs = colorStops[i] #Window.alert("color stop: " + str(cs.offset)) stopPosn = cs.offset #Window.alert("color stopPosn: " + str(stopPosn)) colors += "%d%%" % (int(stopPosn * 100 )) colors += str(cs.color) + "," shapeStr.append("\" colors=\"") shapeStr.append(colors) shapeStr.append("\" focusposition=\"") shapeStr.append(str(focusX)) shapeStr.append("%,") shapeStr.append(str(focusY)) shapeStr.append("%,") shapeStr.append("\" angle=\"") shapeStr.append(str(style.gradient.angle)) def appendStroke(self, shapeStr): shapeStr.append("<v:stroke opacity=\"") shapeStr.append(str(self.context.globalAlpha * self.context.strokeStyle.alpha)) shapeStr.append("\"") if (self.context.strokeStyle.type == 'Gradient'): if len(self.context.strokeStyle.gradient.colorStops) > 0: self.appendGradient(self.context.strokeStyle, shapeStr) else: shapeStr.append(" color=\"") shapeStr.append(str(self.context.strokeStyle.color)) shapeStr.append("\" miterlimit=\"") shapeStr.append(str(self.context.miterLimit)) shapeStr.append("\" joinstyle=\"") shapeStr.append(self.context.lineJoin) shapeStr.append("\" endcap=\"") shapeStr.append(self.context.lineCap) shapeStr.append("\"></v:stroke>") def appendFill(self, shapeStr): shapeStr.append("<v:fill opacity=\"") shapeStr.append(str(self.context.globalAlpha * self.context.fillStyle.alpha)) shapeStr.append("\"") if (self.context.fillStyle.type == 'Gradient'): if len(self.context.fillStyle.gradient.colorStops) > 0: self.appendGradient(self.context.fillStyle, shapeStr) else: shapeStr.append(" color=\"") shapeStr.append(str(self.context.fillStyle.color)) shapeStr.append("\"></v:fill>") def fill(self): if len(self.pathStr) == 0: return shapeStr = [] #JSOStack.getScratchArray() shapeStr.append("<v:shape style=\"position:absolute;width:10;height:10;\" coordsize=\"100,100") shapeStr.append("\" stroked=\"f\" path=\"") shapeStr.append(self.pathStr.join()) shapeStr.append(" e\">") self.appendFill(shapeStr) shapeStr.append("</v:shape>") daStr = ''.join(shapeStr) #Window.alert("Fill: " + daStr) self.insert(self.context.globalCompositeOperation, daStr) def stroke(self): if len(self.pathStr) == 0: return shapeStr = [] #JSOStack.getScratchArray() shapeStr.append("<v:shape style=\"position:absolute;") shapeStr.append("width:10; height:10;") shapeStr.append("\" coordsize=\"100,100") shapeStr.append("\" filled=\"f") shapeStr.append("\" stroked=\"t") shapeStr.append("\" strokeweight=\"") shapeStr.append(str(self.context.lineWidth)) shapeStr.append("px\" path=\"") shapeStr.append(self.pathStr.join()) shapeStr.append(" e\">") self.appendStroke(shapeStr) shapeStr.append("<v:shape>") daStr = ''.join(shapeStr) #Window.alert("Stroke: " + daStr) self.insert(self.context.globalCompositeOperation, daStr) def fillRect(self, x, y, w, h): w += x h += y self.beginPath() self.moveTo(x, y) self.lineTo(x, h) self.lineTo(w, h) self.lineTo(w, y) self.closePath() self.fill() self.pathStr.clear() def getContext(self): return self.context def getCoordX(self, matrix, x, y): coordX = int(math.floor((math.floor(10 * (matrix[0] * x + matrix[1] * y + matrix[2]) - 4.5)))) # record current point to derive bounding box of current open path. self.pathStr.logCoordX(coordX / 10) return coordX def getCoordY(self, matrix, x, y): coordY = int(math.floor((math.floor(10 * (matrix[3] * x + matrix[4] * y + matrix[5]) - 4.5)))) # record current point to derive bounding box of current open path. self.pathStr.logCoordY(coordY / 10) return coordY def getFillStyle(self): return self.context.fillStyle def getGlobalAlpha(self): return self.context.globalAlpha def getGlobalCompositeOperation(self): if self.context.globalCompositeOperation == DESTINATION_OVER: return GWTCanvasConsts.DESTINATION_OVER else: return GWTCanvasConsts.SOURCE_OVER def getLineCap(self): if self.context.lineCap == BUTT: return GWTCanvasConsts.BUTT return self.context.lineCap def getLineJoin(self): return self.context.lineJoin def getLineWidth(self): return self.context.lineWidth def getMiterLimit(self): return self.context.miterLimit def getStrokeStyle(self): return self.context.strokeStyle def lineTo(self, x, y): self.pathStr.append(PathElement.lineTo(x, y, self)) self.currentX = x self.currentY = y def moveTo(self, x, y): self.pathStr.append(PathElement.moveTo(x, y, self)) self.currentX = x self.currentY = y def quadraticCurveTo(self, cpx, cpy, x, y): cp1x = (self.currentX + 2.0 / 3.0 * (cpx - self.currentX)) cp1y = (self.currentY + 2.0 / 3.0 * (cpy - self.currentY)) cp2x = (cp1x + (x - self.currentX) / 3.0) cp2y = (cp1y + (y - self.currentY) / 3.0) self.pathStr.append(PathElement.bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y, self)) self.currentX = x self.currentY = y def rect(self, x, y, w, h): self.pathStr.append(PathElement.moveTo(x, y, self)) self.pathStr.append(PathElement.lineTo(x + w, y, self)) self.pathStr.append(PathElement.lineTo(x + w, y + h, self)) self.pathStr.append(PathElement.lineTo(x, y + h, self)) self.pathStr.append(PathElement.closePath()) self.currentX = x self.currentY = y + h def restoreContext(self): if len(self.contextStack) > 0: self.context = self.contextStack.pop() self.matrix = self.context.matrix def rotate(self, angle): s = math.sin(-angle) c = math.cos(-angle) a = self.matrix[0] b = self.matrix[1] m1 = a * c m2 = b * s self.matrix[0] = m1 - m2 m1 = a * s m2 = b * c self.matrix[1] = m1 + m2 a = self.matrix[3] b = self.matrix[4] m1 = a * c m2 = b * s self.matrix[3] = m1 - m2 m1 = a * s m2 = b * c self.matrix[4] = m1 + m2 def saveContext(self): self.contextStack.append(self.context) self.context = VMLContext(self.context) self.matrix = self.context.matrix def scale(self, x, y): self.context.arcScaleX *= x self.context.arcScaleY *= y self.matrix[0] *= x self.matrix[1] *= y self.matrix[3] *= x self.matrix[4] *= y def setBackgroundColor(self, element, color): DOM.setStyleAttribute(element, "backgroundColor", color) def setCoordHeight(self, elem, height): DOM.setElemAttribute(elem, "width", int(height)) self.clear(0, 0) def setCoordWidth(self, elem, width): DOM.setElemAttribute(elem, "width", int(width)) self.clear(0, 0) def setCurrentX(self, currentX): self.currentX = currentX def setCurrentY(self, currentY): self.currentY = currentY #def setFillStyle(self, gradient): # Window.alert("fillStyle gradient: " + str(gradient)) # self.context.fillGradient = gradient def setFillStyle(self, fillStyle): #Window.alert(str(fillStyle)) self.context.fillStyle = VMLStyle() if isinstance(fillStyle, CanvasGradientImplIE6): self.context.fillStyle.type = 'Gradient' self.context.fillStyle.gradient = fillStyle #Window.alert("gradient fillstyle: " + # str(len(self.context.fillStyle.gradient.colorStops))) else: fillStyle = str(fillStyle).strip() if fillStyle.startswith("rgba("): end = fillStyle.find(")", 12) if end > -1: guts = fillStyle[5:end].split(",") if len(guts) == 4: self.context.fillStyle.alpha = float(guts[3]) self.context.fillStyle.color = \ "rgb(" + guts[0] + "," + guts[1] + "," + guts[2] + ")" else: self.context.fillStyle.color = fillStyle #def setStrokeStyle(self, gradient): # self.context.strokeGradient = gradient def setStrokeStyle(self, strokeStyle): self.context.strokeStyle = VMLStyle() if isinstance(strokeStyle, CanvasGradientImplIE6): self.context.strokeStyle.type = 'Gradient' self.context.strokeStyle.gradient = strokeStyle else: strokeStyle = str(strokeStyle).strip() if strokeStyle.startswith("rgba("): end = strokeStyle.find(")", 12) if end > -1: guts = strokeStyle[5:end].split(",") if len(guts) == 4: self.context.stokeStyle.alpha = float(guts[3]) self.context.strokeStyle.color = \ "rgb(" + guts[0] + "," + guts[1] + "," + guts[2] + ")" else: self.context.strokeStyle.color = strokeStyle def setGlobalAlpha(self, globalAlpha): self.context.globalAlpha = globalAlpha def setGlobalCompositeOperation(self, gco): gco = gco.strip() if gco.lower == GWTCanvasConsts.SOURCE_OVER: self.context.globalCompositeOperation = SOURCE_OVER elif gco.lower == GWTCanvasConsts.DESTINATION_OVER: self.context.globalCompositeOperation = DESTINATION_OVER def setLineCap(self, lineCap): if lineCap.strip().lower == GWTCanvasConsts.BUTT: self.context.lineCap = BUTT else: self.context.lineCap = lineCap def setLineJoin(self, lineJoin): self.context.lineJoin = lineJoin def setLineWidth(self, lineWidth): self.context.lineWidth = lineWidth def setMiterLimit(self, miterLimit): self.context.miterLimit = miterLimit def setParentElement(self, g): self.parentElement = g def setPixelHeight(self, elem, height): DOM.setStyleAttribute(elem, "height", str(height) + "px") self.parentHeight = height def setPixelWidth(self, elem, width): DOM.setStyleAttribute(elem, "width", str(width) + "px") self.parentWidth = width def strokeRect(self, x, y, w, h): w += x h += y self.beginPath() self.moveTo(x, y) self.lineTo(x, h) self.lineTo(w, h) self.lineTo(w, y) self.closePath() self.stroke() self.pathStr.clear() def transform(self, m11, m12, m21, m22, dx, dy): a = self.matrix[0] b = self.matrix[1] self.matrix[0] = a * m11 + b * m12 self.matrix[1] = a * m21 + b * m22 self.matrix[2] += a * dx + b * dy a = self.matrix[3] b = self.matrix[4] self.matrix[3] = a * m11 + b * m12 self.matrix[4] = a * m21 + b * m22 self.matrix[5] += a * dx + b * dy def translate(self, x, y): self.matrix[2] += self.matrix[0] * x + self.matrix[1] * y self.matrix[5] += self.matrix[3] * x + self.matrix[4] * y def insert(self, gco, html): self.parentElement.insertAdjacentHTML(gco, html) """ THERE STILL NEEDS TO BE SOMETHING THAT ALLOWS FOR FONT CONTROL #// Internal text style cache fontStyleCache = {} def processFontStyle(self, styleString): if fontStyleCache[styleString]: return fontStyleCache[styleString] el = document.createElement('div') style = el.style try: style.font = styleString except ex: #// Ignore failures to set to invalid font. return fontStyleCache[styleString] =: style: style.fontStyle || DEFAULT_STYLE.style, variant: style.fontVariant || DEFAULT_STYLE.variant, weight: style.fontWeight || DEFAULT_STYLE.weight, size: style.fontSize || DEFAULT_STYLE.size, family: style.fontFamily || DEFAULT_STYLE.family def getComputedStyle(style, element): computedStyle = {} for p in style: computedStyle[p] = style[p] #// Compute the size canvasFontSize = parseFloat(element.currentStyle.fontSize) fontSize = parseFloat(style['size']) if typeof style['size'] == 'number': computedStyle['size'] = style['size'] elif style['size']['indexOf('px') != -1: computedStyle['size'] = fontSize elif style['size']['indexOf('em') != -1: computedStyle['size'] = canvasFontSize * fontSize elif(style['size']['indexOf('%') != -1: computedStyle['size'] = (canvasFontSize / 100) * fontSize elif style['size']['indexOf('pt') != -1: computedStyle['size'] = fontSize / .75 else: computedStyle['size'] = canvasFontSize #// Different scaling between normal text and VML text. #// This was found using trial and error to get the same size #// as non VML text. computedStyle['size'] *= 0.981 return computedStyle """ def buildStyleString(self, style): return style['style'] + ' ' + style['variant'] + ' ' + \ style['weight'] + ' ' + str(style['size']) + 'px ' + \ style['family'] def encodeHtmlAttribute(self, s): e = s.replace('&', '&') return e.replace('"', '"') def drawText_(self, text, x, y, maxWidth, stroke): delta = 1000 left = 0 right = delta offsetX = 0 offsetY = 0 DEFAULT_STYLE = { 'style': 'normal', 'variant': 'normal', 'weight': 'normal', 'size': 10, 'family': 'sans-serif'} """ fontStyle = getComputedStyle(processFontStyle(self.font), self.element_) fontStyleString = buildStyleString(fontStyle) elementStyle = self.element_.currentStyle textAlign = self.textAlign.toLowerCase() if textAlign == 'left' || textAlign == 'center' || \ textAlign == 'right': pass elif textAlign == 'end': if elementStyle.direction == 'ltr': textAlign = 'right' else: textAlign = 'left' elif textAlign == 'start': if elementStyle.direction == 'rtl': textAlign = 'right' else: textAlign = 'left' else: textAlign = 'left' #// 1.75 is an arbitrary number, as there is no info about #// the text baseline if textBaseline == 'hanging' || textBaseline == 'top': offsetY = fontStyle.size / 1.75 elif textBaseline == 'middle': pass else: # default: # if textBaseline == null: # if textBaseline == 'alphabetic': # if textBaseline == 'ideographic': # if textBaseline == 'bottom': offsetY = -fontStyle.size / 2.25 if textAlign == 'right': left = delta right = 0.05 elif textAlign == 'center': left = right = delta / 2 """ fontStyleString = self.buildStyleString(DEFAULT_STYLE) textAlign = 'left' dX = self.getCoordX(self.matrix, x + offsetX, y + offsetY) dY = self.getCoordY(self.matrix, x + offsetX, y + offsetY) #Window.alert("dX: " + str(dX) + " dY: " + str(dY)) lineStr = [] #JSOStack.getScratchArray() lineStr.append('<v:line from="') lineStr.append(str(-left)) lineStr.append(' 0" to="',) lineStr.append(str(right)) lineStr.append(' 0" ') lineStr.append(' coordsize="100 100" coordorigin="0 0"') lineStr.append('" style="position:absolute;width:1px;height:1px"') if stroke: lineStr.append(' filled="f" stroked="t">') self.appendStroke(lineStr) else: lineStr.append(' filled="t" stroked="f">') self.appendFill(lineStr) skewM = str(self.matrix[0]) + ',' + str(self.matrix[1]) + ',' + \ str(self.matrix[3]) + ',' + str(self.matrix[4]) + ',0,0' #Window.alert(skewM) skewOffset = str(math.floor(dX / 10)) + ',' + \ str(math.floor(dY / 10)) lineStr.append('<v:skew on="t" matrix="') lineStr.append(skewM) lineStr.append('" ') lineStr.append(' offset="') lineStr.append(skewOffset) lineStr.append('" origin="') lineStr.append(str(left)) lineStr.append(' 0" />') lineStr.append('<v:path textpathok="true" />') lineStr.append('<v:textpath on="true" string="') lineStr.append(self.encodeHtmlAttribute(text)) lineStr.append('" style="v-text-align:') lineStr.append(textAlign) lineStr.append(';font:') lineStr.append(self.encodeHtmlAttribute(fontStyleString)) lineStr.append('" /></v:line>') daStr = ''.join(lineStr) #Window.alert("Text: " + daStr) self.insert(self.context.globalCompositeOperation, daStr) def fillText(self, text, x, y, maxWidth=None): self.drawText_(text, x, y, maxWidth, False) def strokeText(self, text, x, y, maxWidth=None): self.drawText_(text, x, y, maxWidth, True) """
class GWTCanvasImplIE6: def __init__(self): try: ns = doc().namespaces.item("v") except: doc().namespaces.add("v", "urn:schemas-microsoft-com:vml") doc().createStyleSheet( ).cssText = "v\\:*{behavior:url(#default#VML);}" """* * This will be used for an array join. Currently a bit faster than * StringBuilder.append() & toString() because of the extra collections * overhead. """ self.pathStr = JSOStack() """* * Stack uses preallocated arrays which makes push() slightly faster than * [].push() since each push is simply an indexed setter. """ self.contextStack = [] self.currentX = 0 self.currentY = 0 self.parentElement = None self.parentHeight = 0 self.parentWidth = 0 def arc(self, x, y, radius, startAngle, endAngle, anticlockwise): self.pathStr.append( PathElement.arc(x, y, radius, startAngle, endAngle, anticlockwise, self)) def beginPath(self): self.pathStr.clear() def clear(self, width=0, height=0): self.pathStr.clear() DOM.setInnerHTML(self.parentElement, "") def closePath(self): self.pathStr.append(PathElement.closePath()) def createElement(self): self.context = VMLContext() self.matrix = self.context.matrix return self.createParentElement() def createParentElement(self): self.parentElement = DOM.createElement("div") DOM.setStyleAttribute(self.parentElement, "overflow", "hidden") return self.parentElement def cubicCurveTo(self, cp1x, cp1y, cp2x, cp2y, x, y): self.pathStr.append( PathElement.bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y, self)) self.currentX = x self.currentY = y def drawImage(self, img, *args): if isinstance(img, Widget): img = img.getElement() fullWidth = img.width fullHeight = img.height if len(args) == 8: sourceX = args[0] sourceY = args[1] sourceWidth = args[2] sourceHeight = args[3] destX = args[4] destY = args[5] destWidth = args[6] destHeight = args[7] elif len(args) == 4: sourceX = 0 sourceY = 0 sourceWidth = fullWidth sourceHeight = fullHeight destX = args[0] destY = args[1] destWidth = args[2] destHeight = args[3] elif len(args) == 2: sourceX = 0 sourceY = 0 sourceWidth = fullWidth sourceHeight = fullHeight destX = args[0] destY = args[1] destWidth = fullWidth destHeight = fullHeight vmlStr = [] # JSOStack.getScratchArray() vmlStr.append("<v:group style=\"position:absolute;width:10;height:10;") dX = self.getCoordX(self.matrix, destX, destY) dY = self.getCoordY(self.matrix, destX, destY) # If we have a transformation matrix with rotation/scale, we # apply a filter if self.context.matrix[0] != 1 or self.context.matrix[1] != 0: # We create a padding bounding box to prevent clipping. vmlStr.append("padding-right:") vmlStr.append(str(self.parentWidth) + "px;") vmlStr.append("padding-bottom:") vmlStr.append(str(self.parentHeight) + "px;") vmlStr.append( "filter:progid:DXImageTransform.Microsoft.Matrix(M11='") vmlStr.append("" + str(self.matrix[0])) vmlStr.append("',") vmlStr.append("M12='") vmlStr.append("" + str(self.matrix[1])) vmlStr.append("',") vmlStr.append("M21='") vmlStr.append(str(self.matrix[3])) vmlStr.append("',") vmlStr.append("M22='") vmlStr.append(str(self.matrix[4])) vmlStr.append("',") vmlStr.append("Dx='") vmlStr.append(str(math.floor(((dX / 10))))) vmlStr.append("',") vmlStr.append("Dy='") vmlStr.append(str(math.floor(((dY / 10))))) vmlStr.append("', SizingMethod='clip');") else: vmlStr.append("left:") vmlStr.append("%dpx;" % int(dX / 10)) vmlStr.append("top:") vmlStr.append("%dpx" % int(dY / 10)) vmlStr.append( "\" coordsize=\"100,100\" coordorigin=\"0,0\"><v:image src=\"") vmlStr.append(DOM.getAttribute(img, "src")) vmlStr.append("\" style=\"") vmlStr.append("width:") vmlStr.append(str(int(destWidth * 10))) vmlStr.append(";height:") vmlStr.append(str(int(destHeight * 10))) vmlStr.append(";\" cropleft=\"") vmlStr.append(str(sourceX / fullWidth)) vmlStr.append("\" croptop=\"") vmlStr.append(str(sourceY / fullHeight)) vmlStr.append("\" cropright=\"") vmlStr.append(str((fullWidth - sourceX - sourceWidth) / fullWidth)) vmlStr.append("\" cropbottom=\"") vmlStr.append(str((fullHeight - sourceY - sourceHeight) / fullHeight)) vmlStr.append("\"/></v:group>") self.insert("BeforeEnd", ''.join(vmlStr)) def fill(self): if len(self.pathStr) == 0: return shapeStr = [] #JSOStack.getScratchArray() shapeStr.append( "<v:shape style=\"position:absolute;width:10;height:10;\" coordsize=\"100,100\" fillcolor=\"" ) shapeStr.append(self.context.fillStyle) shapeStr.append("\" stroked=\"f\" path=\"") shapeStr.append(self.pathStr.join()) shapeStr.append(" e\"><v:fill opacity=\"") shapeStr.append(str(self.context.globalAlpha * self.context.fillAlpha)) if (self.context.fillGradient is not None and len(self.context.fillGradient.colorStops) > 0): colorStops = self.context.fillGradient.colorStops shapeStr.append("\" color=\"") shapeStr.append(str(colorStops[0].color)) shapeStr.append("\" color2=\"") shapeStr.append(str(colorStops[colorStops.size() - 1].color)) shapeStr.append("\" type=\"") shapeStr.append(self.context.fillGradient.type) minX = self.pathStr.getMinCoordX() maxX = self.pathStr.getMaxCoordX() minY = self.pathStr.getMinCoordY() maxY = self.pathStr.getMaxCoordY() dx = maxX - minX dy = maxY - minY fillLength = math.sqrt((dx * dx) + (dy * dy)) gradLength = len(self.context.fillGradient) # Now add all the color stops colors = "" for i in range(1, len(colorStops)): cs = colorStops[i] stopPosn = cs.offset * gradLength # /(math.min(((stopPosn / fillLength) * 100), 100)) colors += "%d%%" % (100 - int(((stopPosn / fillLength) * 100))) colors += str(cs.color) + "," if stopPosn > fillLength: break shapeStr.append("\" colors=\"") # shapeStr.append(colors) shapeStr.append("50% white,51% #0f0,100% #fff,") shapeStr.append("\" angle=\"") #shapeStr.append(str(self.context.fillGradient.angle)) shapeStr.append("180" + "") shapeStr.append("\"></v:fill></v:shape>") daStr = ''.join(shapeStr) # Window.alert(daStr) self.insert(self.context.globalCompositeOperation, daStr) def fillRect(self, x, y, w, h): w += x h += y self.beginPath() self.moveTo(x, y) self.lineTo(x, h) self.lineTo(w, h) self.lineTo(w, y) self.closePath() self.fill() self.pathStr.clear() def getContext(self): return self.context def getCoordX(self, matrix, x, y): coordX = int( math.floor( (math.floor(10 * (matrix[0] * x + matrix[1] * y + matrix[2]) - 4.5)))) # record current point to derive bounding box of current open path. self.pathStr.logCoordX(coordX / 10) return coordX def getCoordY(self, matrix, x, y): coordY = int( math.floor( (math.floor(10 * (matrix[3] * x + matrix[4] * y + matrix[5]) - 4.5)))) # record current point to derive bounding box of current open path. self.pathStr.logCoordY(coordY / 10) return coordY def getFillStyle(self): return self.context.fillStyle def getGlobalAlpha(self): return self.context.globalAlpha def getGlobalCompositeOperation(self): if self.context.globalCompositeOperation == DESTINATION_OVER: return GWTCanvasConsts.DESTINATION_OVER else: return GWTCanvasConsts.SOURCE_OVER def getLineCap(self): if self.context.lineCap == BUTT: return GWTCanvasConsts.BUTT return self.context.lineCap def getLineJoin(self): return self.context.lineJoin def getLineWidth(self): return self.context.lineWidth def getMiterLimit(self): return self.context.miterLimit def getStrokeStyle(self): return self.context.strokeStyle def lineTo(self, x, y): self.pathStr.append(PathElement.lineTo(x, y, self)) self.currentX = x self.currentY = y def moveTo(self, x, y): self.pathStr.append(PathElement.moveTo(x, y, self)) self.currentX = x self.currentY = y def quadraticCurveTo(self, cpx, cpy, x, y): cp1x = (self.currentX + 2.0 / 3.0 * (cpx - self.currentX)) cp1y = (self.currentY + 2.0 / 3.0 * (cpy - self.currentY)) cp2x = (cp1x + (x - self.currentX) / 3.0) cp2y = (cp1y + (y - self.currentY) / 3.0) self.pathStr.append( PathElement.bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y, self)) self.currentX = x self.currentY = y def rect(self, x, y, w, h): self.pathStr.append(PathElement.moveTo(x, y, self)) self.pathStr.append(PathElement.lineTo(x + w, y, self)) self.pathStr.append(PathElement.lineTo(x + w, y + h, self)) self.pathStr.append(PathElement.lineTo(x, y + h, self)) self.pathStr.append(PathElement.closePath()) self.currentX = x self.currentY = y + h def restoreContext(self): if len(self.contextStack) > 0: self.context = self.contextStack.pop() self.matrix = self.context.matrix def rotate(self, angle): s = math.sin(-angle) c = math.cos(-angle) a = self.matrix[0] b = self.matrix[1] m1 = a * c m2 = b * s self.matrix[0] = m1 - m2 m1 = a * s m2 = b * c self.matrix[1] = m1 + m2 a = self.matrix[3] b = self.matrix[4] m1 = a * c m2 = b * s self.matrix[3] = m1 - m2 m1 = a * s m2 = b * c self.matrix[4] = m1 + m2 def saveContext(self): self.contextStack.append(self.context) self.context = VMLContext(self.context) self.matrix = self.context.matrix def scale(self, x, y): self.context.arcScaleX *= x self.context.arcScaleY *= y self.matrix[0] *= x self.matrix[1] *= y self.matrix[3] *= x self.matrix[4] *= y def setBackgroundColor(self, element, color): DOM.setStyleAttribute(element, "backgroundColor", color) def setCoordHeight(self, elem, height): DOM.setElemAttribute(elem, "width", int(height)) self.clear(0, 0) def setCoordWidth(self, elem, width): DOM.setElemAttribute(elem, "width", int(width)) self.clear(0, 0) def setCurrentX(self, currentX): self.currentX = currentX def setCurrentY(self, currentY): self.currentY = currentY def setFillStyle(self, gradient): self.context.fillGradient = gradient def setFillStyle(self, fillStyle): fillStyle = str(fillStyle).strip() if fillStyle.startswith("rgba("): end = fillStyle.find(")", 12) if end > -1: guts = fillStyle[5:end].split(",") if len(guts) == 4: self.context.fillAlpha = float(guts[3]) self.context.fillStyle = "rgb(" + guts[0] + "," + guts[ 1] + "," + guts[2] + ")" else: self.context.fillAlpha = 1 self.context.fillStyle = fillStyle def setGlobalAlpha(self, globalAlpha): self.context.globalAlpha = globalAlpha def setGlobalCompositeOperation(self, gco): gco = gco.strip() if gco.lower == GWTCanvasConsts.SOURCE_OVER: self.context.globalCompositeOperation = SOURCE_OVER elif gco.lower == GWTCanvasConsts.DESTINATION_OVER: self.context.globalCompositeOperation = DESTINATION_OVER def setLineCap(self, lineCap): if lineCap.strip().lower == GWTCanvasConsts.BUTT: self.context.lineCap = BUTT else: self.context.lineCap = lineCap def setLineJoin(self, lineJoin): self.context.lineJoin = lineJoin def setLineWidth(self, lineWidth): self.context.lineWidth = lineWidth def setMiterLimit(self, miterLimit): self.context.miterLimit = miterLimit def setParentElement(self, g): self.parentElement = g def setPixelHeight(self, elem, height): DOM.setStyleAttribute(elem, "height", str(height) + "px") self.parentHeight = height def setPixelWidth(self, elem, width): DOM.setStyleAttribute(elem, "width", str(width) + "px") self.parentWidth = width def setStrokeStyle(self, gradient): self.context.strokeGradient = gradient def setStrokeStyle(self, strokeStyle): strokeStyle = str(strokeStyle).strip() if strokeStyle.startswith("rgba("): end = strokeStyle.find(")", 12) if end > -1: guts = strokeStyle[5:end].split(",") if len(guts) == 4: self.context.strokeAlpha = float(guts[3]) self.context.strokeStyle = "rgb(" + guts[0] + "," + guts[ 1] + "," + guts[2] + ")" else: self.context.strokeAlpha = 1 self.context.strokeStyle = strokeStyle def stroke(self): if len(self.pathStr) == 0: return shapeStr = [] #JSOStack.getScratchArray() shapeStr.append( "<v:shape style=\"position:absolute;width:10;height:10;\" coordsize=\"100,100\" filled=\"f\" strokecolor=\"" ) shapeStr.append(str(self.context.strokeStyle)) shapeStr.append("\" strokeweight=\"") shapeStr.append(str(self.context.lineWidth)) shapeStr.append("px\" path=\"") shapeStr.append(self.pathStr.join()) shapeStr.append(" e\"><v:stroke opacity=\"") shapeStr.append( str(self.context.globalAlpha * self.context.strokeAlpha)) shapeStr.append("\" miterlimit=\"") shapeStr.append(str(self.context.miterLimit)) shapeStr.append("\" joinstyle=\"") shapeStr.append(self.context.lineJoin) shapeStr.append("\" endcap=\"") shapeStr.append(self.context.lineCap) shapeStr.append("\"></v:stroke></v:shape>") self.insert(self.context.globalCompositeOperation, ''.join(shapeStr)) def strokeRect(self, x, y, w, h): w += x h += y self.beginPath() self.moveTo(x, y) self.lineTo(x, h) self.lineTo(w, h) self.lineTo(w, y) self.closePath() self.stroke() self.pathStr.clear() def transform(m11, m12, m21, m22, dx, dy): a = self.matrix[0] b = self.matrix[1] self.matrix[0] = a * m11 + b * m21 self.matrix[1] = a * m12 + b * m22 self.matrix[2] += a * dx + b * dy a = self.matrix[3] b = self.matrix[4] self.matrix[3] = a * m11 + b * m21 self.matrix[4] = a * m12 + b * m22 self.matrix[5] += a * dx + b * dy def translate(self, x, y): self.matrix[2] += self.matrix[0] * x + self.matrix[1] * y self.matrix[5] += self.matrix[3] * x + self.matrix[4] * y def insert(self, gco, html): self.parentElement.insertAdjacentHTML(gco, html)
class GWTCanvasImplIE6: def __init__(self): try: ns = doc().namespaces.item("v") except: doc().namespaces.add("v", "urn:schemas-microsoft-com:vml") doc().createStyleSheet( ).cssText = "v\\:*{behavior:url(#default#VML);}" """* * This will be used for an array join. Currently a bit faster than * StringBuilder.append() & toString() because of the extra collections * overhead. """ self.pathStr = JSOStack() """* * Stack uses preallocated arrays which makes push() slightly faster than * [].push() since each push is simply an indexed setter. """ self.contextStack = [] self.currentX = 0 self.currentY = 0 self.parentElement = None self.parentHeight = 0 self.parentWidth = 0 def arc(self, x, y, radius, startAngle, endAngle, anticlockwise): self.pathStr.append( PathElement.arc(x, y, radius, startAngle, endAngle, anticlockwise, self)) def beginPath(self): self.pathStr.clear() def clear(self, width=0, height=0): self.pathStr.clear() DOM.setInnerHTML(self.parentElement, "") def closePath(self): self.pathStr.append(PathElement.closePath()) def createElement(self): self.context = VMLContext() self.matrix = self.context.matrix return self.createParentElement() def createParentElement(self): self.parentElement = DOM.createElement("div") DOM.setStyleAttribute(self.parentElement, "overflow", "hidden") return self.parentElement def setFont(self, font): pass # NOT IMPLEMENTED def cubicCurveTo(self, cp1x, cp1y, cp2x, cp2y, x, y): self.pathStr.append( PathElement.bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y, self)) self.currentX = x self.currentY = y def drawImage(self, img, *args): if isinstance(img, Widget): img = img.getElement() fullWidth = img.width fullHeight = img.height if len(args) == 8: sourceX = args[0] sourceY = args[1] sourceWidth = args[2] sourceHeight = args[3] destX = args[4] destY = args[5] destWidth = args[6] destHeight = args[7] elif len(args) == 4: sourceX = 0 sourceY = 0 sourceWidth = fullWidth sourceHeight = fullHeight destX = args[0] destY = args[1] destWidth = args[2] destHeight = args[3] elif len(args) == 2: sourceX = 0 sourceY = 0 sourceWidth = fullWidth sourceHeight = fullHeight destX = args[0] destY = args[1] destWidth = fullWidth destHeight = fullHeight vmlStr = [] # JSOStack.getScratchArray() vmlStr.append("<v:group style=\"position:absolute;width:10;height:10;") dX = self.getCoordX(self.matrix, destX, destY) dY = self.getCoordY(self.matrix, destX, destY) # If we have a transformation matrix with rotation/scale, we # apply a filter if self.context.matrix[0] != 1 or self.context.matrix[1] != 0: # We create a padding bounding box to prevent clipping. vmlStr.append("padding-right:") vmlStr.append(str(self.parentWidth) + "px;") vmlStr.append("padding-bottom:") vmlStr.append(str(self.parentHeight) + "px;") vmlStr.append( "filter:progid:DXImageTransform.Microsoft.Matrix(M11='") vmlStr.append("" + str(self.matrix[0])) vmlStr.append("',") vmlStr.append("M12='") vmlStr.append("" + str(self.matrix[1])) vmlStr.append("',") vmlStr.append("M21='") vmlStr.append(str(self.matrix[3])) vmlStr.append("',") vmlStr.append("M22='") vmlStr.append(str(self.matrix[4])) vmlStr.append("',") vmlStr.append("Dx='") vmlStr.append(str(math.floor(((dX / 10))))) vmlStr.append("',") vmlStr.append("Dy='") vmlStr.append(str(math.floor(((dY / 10))))) vmlStr.append("', SizingMethod='clip');") else: vmlStr.append("left:") vmlStr.append("%dpx;" % int(dX / 10)) vmlStr.append("top:") vmlStr.append("%dpx" % int(dY / 10)) vmlStr.append( "\" coordsize=\"100,100\" coordorigin=\"0,0\"><v:image src=\"") vmlStr.append(DOM.getAttribute(img, "src")) vmlStr.append("\" style=\"") vmlStr.append("width:") vmlStr.append(str(int(destWidth * 10))) vmlStr.append(";height:") vmlStr.append(str(int(destHeight * 10))) vmlStr.append(";\" cropleft=\"") vmlStr.append(str(sourceX / fullWidth)) vmlStr.append("\" croptop=\"") vmlStr.append(str(sourceY / fullHeight)) vmlStr.append("\" cropright=\"") vmlStr.append(str((fullWidth - sourceX - sourceWidth) / fullWidth)) vmlStr.append("\" cropbottom=\"") vmlStr.append(str((fullHeight - sourceY - sourceHeight) / fullHeight)) vmlStr.append("\"/></v:group>") self.insert("BeforeEnd", ''.join(vmlStr)) def appendGradient(self, style, shapeStr): colorStops = style.gradient.colorStops length = len(colorStops) shapeStr.append("\" color=\"") shapeStr.append(str(colorStops[0].color)) shapeStr.append("\" color2=\"") shapeStr.append(str(colorStops[length - 1].color)) shapeStr.append("\" type=\"") shapeStr.append(style.gradient.type) if style.gradient.type == 'gradient': #Window.alert(" gdx: " + str(style.gradient.dx) + # " gdy: " + str(style.gradient.dy) + # " gl: " + str(style.gradient.length) + # " ga: " + str(style.gradient.angle)) # Now add all the color stops colors = "" for i in range(1, len(colorStops)): cs = colorStops[i] #Window.alert("color stop offset: " + str(cs.offset)) stopPosn = cs.offset colors += "%d%%" % (int(stopPosn * 100)) colors += str(cs.color) + "," shapeStr.append("\" colors=\"") shapeStr.append(colors) else: """ gradientradial under VML is limited to rectangular gradients see http://msdn.microsoft.com/en-us/library/bb264135%28v=vs.85%29.aspx so while this code is here, the results will never be what the rest of the world would expect - go figure """ minX = self.pathStr.getMinCoordX() maxX = self.pathStr.getMaxCoordX() minY = self.pathStr.getMinCoordY() maxY = self.pathStr.getMaxCoordY() dx = maxX - minX dy = maxY - minY fillLength = math.sqrt((dx * dx) + (dy * dy)) #Window.alert("fillLength: " + str(fillLength) + # " gdx: " + str(style.gradient.dx) + # " gdy: " + str(style.gradient.dy) + # " gl: " + str(style.gradient.length) + # " ga: " + str(style.gradient.angle) + # " gsr: " + str(style.gradient.startRad) + # " ger: " + str(style.gradient.endRad)) # need some proper math to calculate the focus position focusX = 50 focusY = 50 # Now add all the color stops colors = "" for i in range(1, len(colorStops)): cs = colorStops[i] #Window.alert("color stop: " + str(cs.offset)) stopPosn = cs.offset #Window.alert("color stopPosn: " + str(stopPosn)) colors += "%d%%" % (int(stopPosn * 100)) colors += str(cs.color) + "," shapeStr.append("\" colors=\"") shapeStr.append(colors) shapeStr.append("\" focusposition=\"") shapeStr.append(str(focusX)) shapeStr.append("%,") shapeStr.append(str(focusY)) shapeStr.append("%,") shapeStr.append("\" angle=\"") shapeStr.append(str(style.gradient.angle)) def appendStroke(self, shapeStr): shapeStr.append("<v:stroke opacity=\"") shapeStr.append( str(self.context.globalAlpha * self.context.strokeStyle.alpha)) shapeStr.append("\"") if (self.context.strokeStyle.type == 'Gradient'): if len(self.context.strokeStyle.gradient.colorStops) > 0: self.appendGradient(self.context.strokeStyle, shapeStr) else: shapeStr.append(" color=\"") shapeStr.append(str(self.context.strokeStyle.color)) shapeStr.append("\" miterlimit=\"") shapeStr.append(str(self.context.miterLimit)) shapeStr.append("\" joinstyle=\"") shapeStr.append(self.context.lineJoin) shapeStr.append("\" endcap=\"") shapeStr.append(self.context.lineCap) shapeStr.append("\"></v:stroke>") def appendFill(self, shapeStr): shapeStr.append("<v:fill opacity=\"") shapeStr.append( str(self.context.globalAlpha * self.context.fillStyle.alpha)) shapeStr.append("\"") if (self.context.fillStyle.type == 'Gradient'): if len(self.context.fillStyle.gradient.colorStops) > 0: self.appendGradient(self.context.fillStyle, shapeStr) else: shapeStr.append(" color=\"") shapeStr.append(str(self.context.fillStyle.color)) shapeStr.append("\"></v:fill>") def fill(self): if len(self.pathStr) == 0: return shapeStr = [] #JSOStack.getScratchArray() shapeStr.append( "<v:shape style=\"position:absolute;width:10;height:10;\" coordsize=\"100,100" ) shapeStr.append("\" stroked=\"f\" path=\"") shapeStr.append(self.pathStr.join()) shapeStr.append(" e\">") self.appendFill(shapeStr) shapeStr.append("</v:shape>") daStr = ''.join(shapeStr) #Window.alert("Fill: " + daStr) self.insert(self.context.globalCompositeOperation, daStr) def stroke(self): if len(self.pathStr) == 0: return shapeStr = [] #JSOStack.getScratchArray() shapeStr.append("<v:shape style=\"position:absolute;") shapeStr.append("width:10; height:10;") shapeStr.append("\" coordsize=\"100,100") shapeStr.append("\" filled=\"f") shapeStr.append("\" stroked=\"t") shapeStr.append("\" strokeweight=\"") shapeStr.append(str(self.context.lineWidth)) shapeStr.append("px\" path=\"") shapeStr.append(self.pathStr.join()) shapeStr.append(" e\">") self.appendStroke(shapeStr) shapeStr.append("<v:shape>") daStr = ''.join(shapeStr) #Window.alert("Stroke: " + daStr) self.insert(self.context.globalCompositeOperation, daStr) def fillRect(self, x, y, w, h): w += x h += y self.beginPath() self.moveTo(x, y) self.lineTo(x, h) self.lineTo(w, h) self.lineTo(w, y) self.closePath() self.fill() self.pathStr.clear() def getContext(self): return self.context def getCoordX(self, matrix, x, y): coordX = int( math.floor( (math.floor(10 * (matrix[0] * x + matrix[1] * y + matrix[2]) - 4.5)))) # record current point to derive bounding box of current open path. self.pathStr.logCoordX(coordX / 10) return coordX def getCoordY(self, matrix, x, y): coordY = int( math.floor( (math.floor(10 * (matrix[3] * x + matrix[4] * y + matrix[5]) - 4.5)))) # record current point to derive bounding box of current open path. self.pathStr.logCoordY(coordY / 10) return coordY def getFillStyle(self): return self.context.fillStyle def getGlobalAlpha(self): return self.context.globalAlpha def getGlobalCompositeOperation(self): if self.context.globalCompositeOperation == DESTINATION_OVER: return GWTCanvasConsts.DESTINATION_OVER else: return GWTCanvasConsts.SOURCE_OVER def getLineCap(self): if self.context.lineCap == BUTT: return GWTCanvasConsts.BUTT return self.context.lineCap def getLineJoin(self): return self.context.lineJoin def getLineWidth(self): return self.context.lineWidth def getMiterLimit(self): return self.context.miterLimit def getStrokeStyle(self): return self.context.strokeStyle def lineTo(self, x, y): self.pathStr.append(PathElement.lineTo(x, y, self)) self.currentX = x self.currentY = y def moveTo(self, x, y): self.pathStr.append(PathElement.moveTo(x, y, self)) self.currentX = x self.currentY = y def quadraticCurveTo(self, cpx, cpy, x, y): cp1x = (self.currentX + 2.0 / 3.0 * (cpx - self.currentX)) cp1y = (self.currentY + 2.0 / 3.0 * (cpy - self.currentY)) cp2x = (cp1x + (x - self.currentX) / 3.0) cp2y = (cp1y + (y - self.currentY) / 3.0) self.pathStr.append( PathElement.bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y, self)) self.currentX = x self.currentY = y def rect(self, x, y, w, h): self.pathStr.append(PathElement.moveTo(x, y, self)) self.pathStr.append(PathElement.lineTo(x + w, y, self)) self.pathStr.append(PathElement.lineTo(x + w, y + h, self)) self.pathStr.append(PathElement.lineTo(x, y + h, self)) self.pathStr.append(PathElement.closePath()) self.currentX = x self.currentY = y + h def restoreContext(self): if len(self.contextStack) > 0: self.context = self.contextStack.pop() self.matrix = self.context.matrix def rotate(self, angle): s = math.sin(-angle) c = math.cos(-angle) a = self.matrix[0] b = self.matrix[1] m1 = a * c m2 = b * s self.matrix[0] = m1 - m2 m1 = a * s m2 = b * c self.matrix[1] = m1 + m2 a = self.matrix[3] b = self.matrix[4] m1 = a * c m2 = b * s self.matrix[3] = m1 - m2 m1 = a * s m2 = b * c self.matrix[4] = m1 + m2 def saveContext(self): self.contextStack.append(self.context) self.context = VMLContext(self.context) self.matrix = self.context.matrix def scale(self, x, y): self.context.arcScaleX *= x self.context.arcScaleY *= y self.matrix[0] *= x self.matrix[1] *= y self.matrix[3] *= x self.matrix[4] *= y def setBackgroundColor(self, element, color): DOM.setStyleAttribute(element, "backgroundColor", color) def setCoordHeight(self, elem, height): DOM.setElemAttribute(elem, "width", int(height)) self.clear(0, 0) def setCoordWidth(self, elem, width): DOM.setElemAttribute(elem, "width", int(width)) self.clear(0, 0) def setCurrentX(self, currentX): self.currentX = currentX def setCurrentY(self, currentY): self.currentY = currentY #def setFillStyle(self, gradient): # Window.alert("fillStyle gradient: " + str(gradient)) # self.context.fillGradient = gradient def setFillStyle(self, fillStyle): #Window.alert(str(fillStyle)) self.context.fillStyle = VMLStyle() if isinstance(fillStyle, CanvasGradientImplIE6): self.context.fillStyle.type = 'Gradient' self.context.fillStyle.gradient = fillStyle #Window.alert("gradient fillstyle: " + # str(len(self.context.fillStyle.gradient.colorStops))) else: fillStyle = str(fillStyle).strip() if fillStyle.startswith("rgba("): end = fillStyle.find(")", 12) if end > -1: guts = fillStyle[5:end].split(",") if len(guts) == 4: self.context.fillStyle.alpha = float(guts[3]) self.context.fillStyle.color = \ "rgb(" + guts[0] + "," + guts[1] + "," + guts[2] + ")" else: self.context.fillStyle.color = fillStyle #def setStrokeStyle(self, gradient): # self.context.strokeGradient = gradient def setStrokeStyle(self, strokeStyle): self.context.strokeStyle = VMLStyle() if isinstance(strokeStyle, CanvasGradientImplIE6): self.context.strokeStyle.type = 'Gradient' self.context.strokeStyle.gradient = strokeStyle else: strokeStyle = str(strokeStyle).strip() if strokeStyle.startswith("rgba("): end = strokeStyle.find(")", 12) if end > -1: guts = strokeStyle[5:end].split(",") if len(guts) == 4: self.context.stokeStyle.alpha = float(guts[3]) self.context.strokeStyle.color = \ "rgb(" + guts[0] + "," + guts[1] + "," + guts[2] + ")" else: self.context.strokeStyle.color = strokeStyle def setGlobalAlpha(self, globalAlpha): self.context.globalAlpha = globalAlpha def setGlobalCompositeOperation(self, gco): gco = gco.strip() if gco.lower == GWTCanvasConsts.SOURCE_OVER: self.context.globalCompositeOperation = SOURCE_OVER elif gco.lower == GWTCanvasConsts.DESTINATION_OVER: self.context.globalCompositeOperation = DESTINATION_OVER def setLineCap(self, lineCap): if lineCap.strip().lower == GWTCanvasConsts.BUTT: self.context.lineCap = BUTT else: self.context.lineCap = lineCap def setLineJoin(self, lineJoin): self.context.lineJoin = lineJoin def setLineWidth(self, lineWidth): self.context.lineWidth = lineWidth def setMiterLimit(self, miterLimit): self.context.miterLimit = miterLimit def setParentElement(self, g): self.parentElement = g def setPixelHeight(self, elem, height): DOM.setStyleAttribute(elem, "height", str(height) + "px") self.parentHeight = height def setPixelWidth(self, elem, width): DOM.setStyleAttribute(elem, "width", str(width) + "px") self.parentWidth = width def strokeRect(self, x, y, w, h): w += x h += y self.beginPath() self.moveTo(x, y) self.lineTo(x, h) self.lineTo(w, h) self.lineTo(w, y) self.closePath() self.stroke() self.pathStr.clear() def transform(m11, m12, m21, m22, dx, dy): a = self.matrix[0] b = self.matrix[1] self.matrix[0] = a * m11 + b * m21 self.matrix[1] = a * m12 + b * m22 self.matrix[2] += a * dx + b * dy a = self.matrix[3] b = self.matrix[4] self.matrix[3] = a * m11 + b * m21 self.matrix[4] = a * m12 + b * m22 self.matrix[5] += a * dx + b * dy def translate(self, x, y): self.matrix[2] += self.matrix[0] * x + self.matrix[1] * y self.matrix[5] += self.matrix[3] * x + self.matrix[4] * y def insert(self, gco, html): self.parentElement.insertAdjacentHTML(gco, html) """ THERE STILL NEEDS TO BE SOMETHING THAT ALLOWS FOR FONT CONTROL #// Internal text style cache fontStyleCache = {} def processFontStyle(self, styleString): if fontStyleCache[styleString]: return fontStyleCache[styleString] el = document.createElement('div') style = el.style try: style.font = styleString except ex: #// Ignore failures to set to invalid font. return fontStyleCache[styleString] =: style: style.fontStyle || DEFAULT_STYLE.style, variant: style.fontVariant || DEFAULT_STYLE.variant, weight: style.fontWeight || DEFAULT_STYLE.weight, size: style.fontSize || DEFAULT_STYLE.size, family: style.fontFamily || DEFAULT_STYLE.family def getComputedStyle(style, element): computedStyle = {} for p in style: computedStyle[p] = style[p] #// Compute the size canvasFontSize = parseFloat(element.currentStyle.fontSize) fontSize = parseFloat(style['size']) if typeof style['size'] == 'number': computedStyle['size'] = style['size'] elif style['size']['indexOf('px') != -1: computedStyle['size'] = fontSize elif style['size']['indexOf('em') != -1: computedStyle['size'] = canvasFontSize * fontSize elif(style['size']['indexOf('%') != -1: computedStyle['size'] = (canvasFontSize / 100) * fontSize elif style['size']['indexOf('pt') != -1: computedStyle['size'] = fontSize / .75 else: computedStyle['size'] = canvasFontSize #// Different scaling between normal text and VML text. #// This was found using trial and error to get the same size #// as non VML text. computedStyle['size'] *= 0.981 return computedStyle """ def buildStyleString(self, style): return style['style'] + ' ' + style['variant'] + ' ' + \ style['weight'] + ' ' + str(style['size']) + 'px ' + \ style['family'] def encodeHtmlAttribute(self, s): e = s.replace('&', '&') return e.replace('"', '"') def drawText_(self, text, x, y, maxWidth, stroke): delta = 1000 left = 0 right = delta offsetX = 0 offsetY = 0 DEFAULT_STYLE = { 'style': 'normal', 'variant': 'normal', 'weight': 'normal', 'size': 10, 'family': 'sans-serif' } """ fontStyle = getComputedStyle(processFontStyle(self.font), self.element_) fontStyleString = buildStyleString(fontStyle) elementStyle = self.element_.currentStyle textAlign = self.textAlign.toLowerCase() if textAlign == 'left' || textAlign == 'center' || \ textAlign == 'right': pass elif textAlign == 'end': if elementStyle.direction == 'ltr': textAlign = 'right' else: textAlign = 'left' elif textAlign == 'start': if elementStyle.direction == 'rtl': textAlign = 'right' else: textAlign = 'left' else: textAlign = 'left' #// 1.75 is an arbitrary number, as there is no info about #// the text baseline if textBaseline == 'hanging' || textBaseline == 'top': offsetY = fontStyle.size / 1.75 elif textBaseline == 'middle': pass else: # default: # if textBaseline == null: # if textBaseline == 'alphabetic': # if textBaseline == 'ideographic': # if textBaseline == 'bottom': offsetY = -fontStyle.size / 2.25 if textAlign == 'right': left = delta right = 0.05 elif textAlign == 'center': left = right = delta / 2 """ fontStyleString = self.buildStyleString(DEFAULT_STYLE) textAlign = 'left' dX = self.getCoordX(self.matrix, x + offsetX, y + offsetY) dY = self.getCoordY(self.matrix, x + offsetX, y + offsetY) #Window.alert("dX: " + str(dX) + " dY: " + str(dY)) lineStr = [] #JSOStack.getScratchArray() lineStr.append('<v:line from="') lineStr.append(str(-left)) lineStr.append(' 0" to="', ) lineStr.append(str(right)) lineStr.append(' 0" ') lineStr.append(' coordsize="100 100" coordorigin="0 0"') lineStr.append('" style="position:absolute;width:1px;height:1px"') if stroke: lineStr.append(' filled="f" stroked="t">') self.appendStroke(lineStr) else: lineStr.append(' filled="t" stroked="f">') self.appendFill(lineStr) skewM = str(self.matrix[0]) + ',' + str(self.matrix[1]) + ',' + \ str(self.matrix[3]) + ',' + str(self.matrix[4]) + ',0,0' #Window.alert(skewM) skewOffset = str(math.floor(dX / 10)) + ',' + \ str(math.floor(dY / 10)) lineStr.append('<v:skew on="t" matrix="') lineStr.append(skewM) lineStr.append('" ') lineStr.append(' offset="') lineStr.append(skewOffset) lineStr.append('" origin="') lineStr.append(str(left)) lineStr.append(' 0" />') lineStr.append('<v:path textpathok="true" />') lineStr.append('<v:textpath on="true" string="') lineStr.append(self.encodeHtmlAttribute(text)) lineStr.append('" style="v-text-align:') lineStr.append(textAlign) lineStr.append(';font:') lineStr.append(self.encodeHtmlAttribute(fontStyleString)) lineStr.append('" /></v:line>') daStr = ''.join(lineStr) #Window.alert("Text: " + daStr) self.insert(self.context.globalCompositeOperation, daStr) def fillText(self, text, x, y, maxWidth=None): self.drawText_(text, x, y, maxWidth, False) def strokeText(self, text, x, y, maxWidth=None): self.drawText_(text, x, y, maxWidth, True) """
class GWTCanvasImplIE6: def __init__(self): try: ns = doc().namespaces.item("v") except: doc().namespaces.add("v", "urn:schemas-microsoft-com:vml") doc().createStyleSheet().cssText = "v\\:*{behavior:url(#default#VML);}" """* * This will be used for an array join. Currently a bit faster than * StringBuilder.append() & toString() because of the extra collections * overhead. """ self.pathStr = JSOStack() """* * Stack uses preallocated arrays which makes push() slightly faster than * [].push() since each push is simply an indexed setter. """ self.contextStack = [] self.currentX = 0 self.currentY = 0 self.parentElement = None self.parentHeight = 0 self.parentWidth = 0 def arc(self, x, y, radius, startAngle, endAngle, anticlockwise): self.pathStr.append(PathElement.arc(x, y, radius, startAngle, endAngle, anticlockwise, self)) def beginPath(self): self.pathStr.clear() def clear(self, width=0, height=0): self.pathStr.clear() DOM.setInnerHTML(self.parentElement, "") def closePath(self): self.pathStr.append(PathElement.closePath()) def createElement(self): self.context = VMLContext() self.matrix = self.context.matrix return self.createParentElement() def createParentElement(self): self.parentElement = DOM.createElement("div") DOM.setStyleAttribute(self.parentElement, "overflow", "hidden") return self.parentElement def cubicCurveTo(self, cp1x, cp1y, cp2x, cp2y, x, y): self.pathStr.append(PathElement.bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y, self)) self.currentX = x self.currentY = y def drawImage(self, img, *args): if isinstance(img, Widget): img = img.getElement() fullWidth = img.width fullHeight = img.height if len(args) == 8: sourceX = args[0] sourceY = args[1] sourceWidth = args[2] sourceHeight = args[3] destX = args[4] destY = args[5] destWidth = args[6] destHeight = args[7] elif len(args) == 4: sourceX = 0 sourceY = 0 sourceWidth = fullWidth sourceHeight = fullHeight destX = args[0] destY = args[1] destWidth = args[2] destHeight = args[3] elif len(args) == 2: sourceX = 0 sourceY = 0 sourceWidth = fullWidth sourceHeight = fullHeight destX = args[0] destY = args[1] destWidth = fullWidth destHeight = fullHeight vmlStr = [] # JSOStack.getScratchArray() vmlStr.append('<v:group style="position:absolute;width:10;height:10;') dX = self.getCoordX(self.matrix, destX, destY) dY = self.getCoordY(self.matrix, destX, destY) # If we have a transformation matrix with rotation/scale, we # apply a filter if self.context.matrix[0] != 1 or self.context.matrix[1] != 0: # We create a padding bounding box to prevent clipping. vmlStr.append("padding-right:") vmlStr.append(str(self.parentWidth) + "px;") vmlStr.append("padding-bottom:") vmlStr.append(str(self.parentHeight) + "px;") vmlStr.append("filter:progid:DXImageTransform.Microsoft.Matrix(M11='") vmlStr.append("" + str(self.matrix[0])) vmlStr.append("',") vmlStr.append("M12='") vmlStr.append("" + str(self.matrix[1])) vmlStr.append("',") vmlStr.append("M21='") vmlStr.append(str(self.matrix[3])) vmlStr.append("',") vmlStr.append("M22='") vmlStr.append(str(self.matrix[4])) vmlStr.append("',") vmlStr.append("Dx='") vmlStr.append(str(math.floor(((dX / 10))))) vmlStr.append("',") vmlStr.append("Dy='") vmlStr.append(str(math.floor(((dY / 10))))) vmlStr.append("', SizingMethod='clip');") else: vmlStr.append("left:") vmlStr.append("%dpx;" % int(dX / 10)) vmlStr.append("top:") vmlStr.append("%dpx" % int(dY / 10)) vmlStr.append('" coordsize="100,100" coordorigin="0,0"><v:image src="') vmlStr.append(DOM.getAttribute(img, "src")) vmlStr.append('" style="') vmlStr.append("width:") vmlStr.append(str(int(destWidth * 10))) vmlStr.append(";height:") vmlStr.append(str(int(destHeight * 10))) vmlStr.append(';" cropleft="') vmlStr.append(str(sourceX / fullWidth)) vmlStr.append('" croptop="') vmlStr.append(str(sourceY / fullHeight)) vmlStr.append('" cropright="') vmlStr.append(str((fullWidth - sourceX - sourceWidth) / fullWidth)) vmlStr.append('" cropbottom="') vmlStr.append(str((fullHeight - sourceY - sourceHeight) / fullHeight)) vmlStr.append('"/></v:group>') self.insert("BeforeEnd", "".join(vmlStr)) def fill(self): if len(self.pathStr) == 0: return shapeStr = [] # JSOStack.getScratchArray() shapeStr.append('<v:shape style="position:absolute;width:10;height:10;" coordsize="100,100" fillcolor="') shapeStr.append(self.context.fillStyle) shapeStr.append('" stroked="f" path="') shapeStr.append(self.pathStr.join()) shapeStr.append(' e"><v:fill opacity="') shapeStr.append(str(self.context.globalAlpha * self.context.fillAlpha)) if self.context.fillGradient is not None and len(self.context.fillGradient.colorStops) > 0: colorStops = self.context.fillGradient.colorStops shapeStr.append('" color="') shapeStr.append(str(colorStops[0].color)) shapeStr.append('" color2="') shapeStr.append(str(colorStops[colorStops.size() - 1].color)) shapeStr.append('" type="') shapeStr.append(self.context.fillGradient.type) minX = self.pathStr.getMinCoordX() maxX = self.pathStr.getMaxCoordX() minY = self.pathStr.getMinCoordY() maxY = self.pathStr.getMaxCoordY() dx = maxX - minX dy = maxY - minY fillLength = math.sqrt((dx * dx) + (dy * dy)) gradLength = len(self.context.fillGradient) # Now add all the color stops colors = "" for i in range(1, len(colorStops)): cs = colorStops[i] stopPosn = cs.offset * gradLength # /(math.min(((stopPosn / fillLength) * 100), 100)) colors += "%d%%" % (100 - int(((stopPosn / fillLength) * 100))) colors += str(cs.color) + "," if stopPosn > fillLength: break shapeStr.append('" colors="') # shapeStr.append(colors) shapeStr.append("50% white,51% #0f0,100% #fff,") shapeStr.append('" angle="') # shapeStr.append(str(self.context.fillGradient.angle)) shapeStr.append("180" + "") shapeStr.append('"></v:fill></v:shape>') daStr = "".join(shapeStr) # Window.alert(daStr) self.insert(self.context.globalCompositeOperation, daStr) def fillRect(self, x, y, w, h): w += x h += y self.beginPath() self.moveTo(x, y) self.lineTo(x, h) self.lineTo(w, h) self.lineTo(w, y) self.closePath() self.fill() self.pathStr.clear() def getContext(self): return self.context def getCoordX(self, matrix, x, y): coordX = int(math.floor((math.floor(10 * (matrix[0] * x + matrix[1] * y + matrix[2]) - 4.5)))) # record current point to derive bounding box of current open path. self.pathStr.logCoordX(coordX / 10) return coordX def getCoordY(self, matrix, x, y): coordY = int(math.floor((math.floor(10 * (matrix[3] * x + matrix[4] * y + matrix[5]) - 4.5)))) # record current point to derive bounding box of current open path. self.pathStr.logCoordY(coordY / 10) return coordY def getFillStyle(self): return self.context.fillStyle def getGlobalAlpha(self): return self.context.globalAlpha def getGlobalCompositeOperation(self): if self.context.globalCompositeOperation == DESTINATION_OVER: return GWTCanvasConsts.DESTINATION_OVER else: return GWTCanvasConsts.SOURCE_OVER def getLineCap(self): if self.context.lineCap == BUTT: return GWTCanvasConsts.BUTT return self.context.lineCap def getLineJoin(self): return self.context.lineJoin def getLineWidth(self): return self.context.lineWidth def getMiterLimit(self): return self.context.miterLimit def getStrokeStyle(self): return self.context.strokeStyle def lineTo(self, x, y): self.pathStr.append(PathElement.lineTo(x, y, self)) self.currentX = x self.currentY = y def moveTo(self, x, y): self.pathStr.append(PathElement.moveTo(x, y, self)) self.currentX = x self.currentY = y def quadraticCurveTo(self, cpx, cpy, x, y): cp1x = self.currentX + 2.0 / 3.0 * (cpx - self.currentX) cp1y = self.currentY + 2.0 / 3.0 * (cpy - self.currentY) cp2x = cp1x + (x - self.currentX) / 3.0 cp2y = cp1y + (y - self.currentY) / 3.0 self.pathStr.append(PathElement.bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y, self)) self.currentX = x self.currentY = y def rect(self, x, y, w, h): self.pathStr.append(PathElement.moveTo(x, y, self)) self.pathStr.append(PathElement.lineTo(x + w, y, self)) self.pathStr.append(PathElement.lineTo(x + w, y + h, self)) self.pathStr.append(PathElement.lineTo(x, y + h, self)) self.pathStr.append(PathElement.closePath()) self.currentX = x self.currentY = y + h def restoreContext(self): if len(self.contextStack) > 0: self.context = self.contextStack.pop() self.matrix = self.context.matrix def rotate(self, angle): s = math.sin(-angle) c = math.cos(-angle) a = self.matrix[0] b = self.matrix[1] m1 = a * c m2 = b * s self.matrix[0] = m1 - m2 m1 = a * s m2 = b * c self.matrix[1] = m1 + m2 a = self.matrix[3] b = self.matrix[4] m1 = a * c m2 = b * s self.matrix[3] = m1 - m2 m1 = a * s m2 = b * c self.matrix[4] = m1 + m2 def saveContext(self): self.contextStack.append(self.context) self.context = VMLContext(self.context) self.matrix = self.context.matrix def scale(self, x, y): self.context.arcScaleX *= x self.context.arcScaleY *= y self.matrix[0] *= x self.matrix[1] *= y self.matrix[3] *= x self.matrix[4] *= y def setBackgroundColor(self, element, color): DOM.setStyleAttribute(element, "backgroundColor", color) def setCoordHeight(self, elem, height): DOM.setElemAttribute(elem, "width", int(height)) self.clear(0, 0) def setCoordWidth(self, elem, width): DOM.setElemAttribute(elem, "width", int(width)) self.clear(0, 0) def setCurrentX(self, currentX): self.currentX = currentX def setCurrentY(self, currentY): self.currentY = currentY def setFillStyle(self, gradient): self.context.fillGradient = gradient def setFillStyle(self, fillStyle): fillStyle = str(fillStyle).strip() if fillStyle.startswith("rgba("): end = fillStyle.find(")", 12) if end > -1: guts = fillStyle[5:end].split(",") if len(guts) == 4: self.context.fillAlpha = float(guts[3]) self.context.fillStyle = "rgb(" + guts[0] + "," + guts[1] + "," + guts[2] + ")" else: self.context.fillAlpha = 1 self.context.fillStyle = fillStyle def setGlobalAlpha(self, globalAlpha): self.context.globalAlpha = globalAlpha def setGlobalCompositeOperation(self, gco): gco = gco.strip() if gco.lower == GWTCanvasConsts.SOURCE_OVER: self.context.globalCompositeOperation = SOURCE_OVER elif gco.lower == GWTCanvasConsts.DESTINATION_OVER: self.context.globalCompositeOperation = DESTINATION_OVER def setLineCap(self, lineCap): if lineCap.strip().lower == GWTCanvasConsts.BUTT: self.context.lineCap = BUTT else: self.context.lineCap = lineCap def setLineJoin(self, lineJoin): self.context.lineJoin = lineJoin def setLineWidth(self, lineWidth): self.context.lineWidth = lineWidth def setMiterLimit(self, miterLimit): self.context.miterLimit = miterLimit def setParentElement(self, g): self.parentElement = g def setPixelHeight(self, elem, height): DOM.setStyleAttribute(elem, "height", str(height) + "px") self.parentHeight = height def setPixelWidth(self, elem, width): DOM.setStyleAttribute(elem, "width", str(width) + "px") self.parentWidth = width def setStrokeStyle(self, gradient): self.context.strokeGradient = gradient def setStrokeStyle(self, strokeStyle): strokeStyle = str(strokeStyle).strip() if strokeStyle.startswith("rgba("): end = strokeStyle.find(")", 12) if end > -1: guts = strokeStyle[5:end].split(",") if len(guts) == 4: self.context.strokeAlpha = float(guts[3]) self.context.strokeStyle = "rgb(" + guts[0] + "," + guts[1] + "," + guts[2] + ")" else: self.context.strokeAlpha = 1 self.context.strokeStyle = strokeStyle def stroke(self): if len(self.pathStr) == 0: return shapeStr = [] # JSOStack.getScratchArray() shapeStr.append( '<v:shape style="position:absolute;width:10;height:10;" coordsize="100,100" filled="f" strokecolor="' ) shapeStr.append(str(self.context.strokeStyle)) shapeStr.append('" strokeweight="') shapeStr.append(str(self.context.lineWidth)) shapeStr.append('px" path="') shapeStr.append(self.pathStr.join()) shapeStr.append(' e"><v:stroke opacity="') shapeStr.append(str(self.context.globalAlpha * self.context.strokeAlpha)) shapeStr.append('" miterlimit="') shapeStr.append(str(self.context.miterLimit)) shapeStr.append('" joinstyle="') shapeStr.append(self.context.lineJoin) shapeStr.append('" endcap="') shapeStr.append(self.context.lineCap) shapeStr.append('"></v:stroke></v:shape>') self.insert(self.context.globalCompositeOperation, "".join(shapeStr)) def strokeRect(self, x, y, w, h): w += x h += y self.beginPath() self.moveTo(x, y) self.lineTo(x, h) self.lineTo(w, h) self.lineTo(w, y) self.closePath() self.stroke() self.pathStr.clear() def transform(m11, m12, m21, m22, dx, dy): a = self.matrix[0] b = self.matrix[1] self.matrix[0] = a * m11 + b * m21 self.matrix[1] = a * m12 + b * m22 self.matrix[2] += a * dx + b * dy a = self.matrix[3] b = self.matrix[4] self.matrix[3] = a * m11 + b * m21 self.matrix[4] = a * m12 + b * m22 self.matrix[5] += a * dx + b * dy def translate(self, x, y): self.matrix[2] += self.matrix[0] * x + self.matrix[1] * y self.matrix[5] += self.matrix[3] * x + self.matrix[4] * y def insert(self, gco, html): self.parentElement.insertAdjacentHTML(gco, html)