1 """
2 * Copyright 2008 Google Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5 * use this file except in compliance with the License. You may obtain a copy of
6 * the License at
7 *
8 * http:#www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 * License for the specific language governing permissions and limitations under
14 * the License.
15 """
16
17 import math
18
19 from pyjamas import DOM
20 from __pyjamas__ import JS, doc
21 from pyjamas.ui.Widget import Widget
22
23
24
25 from pyjamas.Canvas.GWTCanvasImplIEConsts import BUTT, DESTINATION_OVER, SOURCE_OVER
26 from pyjamas.Canvas import GWTCanvasConsts
27 from pyjamas.Canvas.JSOStack import JSOStack
28 from pyjamas.Canvas import PathElement
29 from pyjamas.Canvas.VMLContext import VMLContext
30
32 JS("""
33 if (!$doc.namespaces["v"]) {
34 $doc.namespaces.add("v", "urn:schemas-microsoft-com:vml");
35 $doc.createStyleSheet().cssText = "v\\:*{behavior:url(#default#VML);}";
36 }
37 """)
38
39
40 """*
41 * Deferred binding implementation of GWTCanvas for IE6. It is an implementation
42 * of canvas on top of VML.
43 """
45
47 try:
48 ns = doc().namespaces.item("v")
49 except:
50 doc().namespaces.add("v", "urn:schemas-microsoft-com:vml")
51 doc().createStyleSheet().cssText = "v\\:*{behavior:url(#default#VML);}"
52
53
54
55 """*
56 * This will be used for an array join. Currently a bit faster than
57 * StringBuilder.append() & toString() because of the extra collections
58 * overhead.
59 """
60 self.pathStr = JSOStack()
61
62 """*
63 * Stack uses preallocated arrays which makes push() slightly faster than
64 * [].push() since each push is simply an indexed setter.
65 """
66 self.contextStack = []
67
68 self.currentX = 0
69
70 self.currentY = 0
71
72 self.parentElement = None
73
74 self.parentHeight = 0
75
76 self.parentWidth = 0
77
78
79
80 - def arc(self, x, y, radius, startAngle, endAngle, anticlockwise):
83
84
87
88
89 - def clear(self, width=0, height=0):
92
95
96
101
102
107
108
113
114
116
117 if isinstance(img, Widget):
118 img = img.getElement()
119 fullWidth = img.width
120 fullHeight = img.height
121
122 if len(args) == 8:
123 sourceX = args[0]
124 sourceY = args[1]
125 sourceWidth = args[2]
126 sourceHeight = args[3]
127 destX = args[4]
128 destY = args[5]
129 destWidth = args[6]
130 destHeight = args[7]
131 elif len(args) == 4:
132 sourceX = 0
133 sourceY = 0
134 sourceWidth = fullWidth
135 sourceHeight = fullHeight
136 destX = args[0]
137 destY = args[1]
138 destWidth = args[2]
139 destHeight = args[3]
140 elif len(args) == 2:
141 sourceX = 0
142 sourceY = 0
143 sourceWidth = fullWidth
144 sourceHeight = fullHeight
145 destX = args[0]
146 destY = args[1]
147 destWidth = fullWidth
148 destHeight = fullHeight
149
150 vmlStr = []
151
152 vmlStr.append("<v:group style=\"position:absolute;width:10;height:10;")
153 dX = self.getCoordX(self.matrix, destX, destY)
154 dY = self.getCoordY(self.matrix, destX, destY)
155
156
157
158 if self.context.matrix[0] != 1 or self.context.matrix[1] != 0:
159
160
161 vmlStr.append("padding-right:")
162 vmlStr.append(str(self.parentWidth) + "px;")
163 vmlStr.append("padding-bottom:")
164 vmlStr.append(str(self.parentHeight) + "px;")
165 vmlStr.append("filter:progid:DXImageTransform.Microsoft.Matrix(M11='")
166 vmlStr.append("" + str(self.matrix[0]))
167 vmlStr.append("',")
168 vmlStr.append("M12='")
169 vmlStr.append("" + str(self.matrix[1]))
170 vmlStr.append("',")
171 vmlStr.append("M21='")
172 vmlStr.append(str(self.matrix[3]))
173 vmlStr.append("',")
174 vmlStr.append("M22='")
175 vmlStr.append(str(self.matrix[4]))
176 vmlStr.append("',")
177 vmlStr.append("Dx='")
178 vmlStr.append(str(math.floor(((dX / 10)))))
179 vmlStr.append("',")
180 vmlStr.append("Dy='")
181 vmlStr.append(str(math.floor(((dY / 10)))))
182 vmlStr.append("', SizingMethod='clip');")
183
184 else:
185 vmlStr.append("left:")
186 vmlStr.append("%dpx;" % int(dX / 10))
187 vmlStr.append("top:")
188 vmlStr.append("%dpx" % int(dY / 10))
189
190
191 vmlStr.append("\" coordsize=\"100,100\" coordorigin=\"0,0\"><v:image src=\"")
192 vmlStr.append(DOM.getAttribute(img, "src"))
193 vmlStr.append("\" style=\"")
194
195 vmlStr.append("width:")
196 vmlStr.append(str(int(destWidth * 10)))
197 vmlStr.append(";height:")
198 vmlStr.append(str(int(destHeight * 10)))
199 vmlStr.append(";\" cropleft=\"")
200 vmlStr.append(str(sourceX / fullWidth))
201 vmlStr.append("\" croptop=\"")
202 vmlStr.append(str(sourceY / fullHeight))
203 vmlStr.append("\" cropright=\"")
204 vmlStr.append(str((fullWidth - sourceX - sourceWidth) / fullWidth))
205 vmlStr.append("\" cropbottom=\"")
206 vmlStr.append(str((fullHeight - sourceY - sourceHeight) / fullHeight))
207 vmlStr.append("\"/></v:group>")
208
209 self.insert("BeforeEnd", ''.join(vmlStr))
210
211
213 if len(self.pathStr) == 0:
214 return
215
216 shapeStr = []
217 shapeStr.append("<v:shape style=\"position:absolute;width:10;height:10;\" coordsize=\"100,100\" fillcolor=\"")
218 shapeStr.append(self.context.fillStyle)
219 shapeStr.append("\" stroked=\"f\" path=\"")
220
221 shapeStr.append(self.pathStr.join())
222
223 shapeStr.append(" e\"><v:fill opacity=\"")
224 shapeStr.append(str(self.context.globalAlpha * self.context.fillAlpha))
225
226 if (self.context.fillGradient is not None and
227 len(self.context.fillGradient.colorStops) > 0):
228 colorStops = self.context.fillGradient.colorStops
229
230 shapeStr.append("\" color=\"")
231 shapeStr.append(str(colorStops[0].color))
232 shapeStr.append("\" color2=\"")
233 shapeStr.append(str(colorStops[colorStops.size() - 1].color))
234 shapeStr.append("\" type=\"")
235 shapeStr.append(self.context.fillGradient.type)
236
237 minX = self.pathStr.getMinCoordX()
238 maxX = self.pathStr.getMaxCoordX()
239 minY = self.pathStr.getMinCoordY()
240 maxY = self.pathStr.getMaxCoordY()
241
242 dx = maxX - minX
243 dy = maxY - minY
244
245 fillLength = math.sqrt((dx * dx) + (dy * dy))
246 gradLength = len(self.context.fillGradient)
247
248
249 colors = ""
250 for i in range(1, len(colorStops)):
251 cs = colorStops[i]
252 stopPosn = cs.offset * gradLength
253
254 colors += "%d%%" % (100 - int(((stopPosn / fillLength) * 100)))
255 colors += str(cs.color) + ","
256 if stopPosn > fillLength:
257 break
258
259
260 shapeStr.append("\" colors=\"")
261
262 shapeStr.append("50% white,51% #0f0,100% #fff,")
263 shapeStr.append("\" angle=\"")
264
265 shapeStr.append("180" + "")
266
267
268 shapeStr.append("\"></v:fill></v:shape>")
269 daStr = ''.join(shapeStr)
270
271 self.insert(self.context.globalCompositeOperation, daStr)
272
273
285
286
287 - def getContext(self):
289
290
292 coordX = int(math.floor((math.floor(10 * (matrix[0] * x + matrix[1]
293 * y + matrix[2]) - 4.5))))
294
295 self.pathStr.logCoordX(coordX / 10)
296 return coordX
297
298
300 coordY = int(math.floor((math.floor(10 * (matrix[3] * x + matrix[4]
301 * y + matrix[5]) - 4.5))))
302
303 self.pathStr.logCoordY(coordY / 10)
304 return coordY
305
306
308 return self.context.fillStyle
309
310
312 return self.context.globalAlpha
313
314
320
321
322
328
329
331 return self.context.lineJoin
332
333
335 return self.context.lineWidth
336
337
339 return self.context.miterLimit
340
341
343 return self.context.strokeStyle
344
345
350
351
356
357
359 cp1x = (self.currentX + 2.0 / 3.0 * (cpx - self.currentX))
360 cp1y = (self.currentY + 2.0 / 3.0 * (cpy - self.currentY))
361 cp2x = (cp1x + (x - self.currentX) / 3.0)
362 cp2y = (cp1y + (y - self.currentY) / 3.0)
363 self.pathStr.append(PathElement.bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y, self))
364 self.currentX = x
365 self.currentY = y
366
367
368 - def rect(self, x, y, w, h):
376
377
378 - def restoreContext(self):
379 if len(self.contextStack) > 0:
380 self.context = self.contextStack.pop()
381 self.matrix = self.context.matrix
382
383
384
386 s = math.sin(-angle)
387 c = math.cos(-angle)
388 a = self.matrix[0]
389 b = self.matrix[1]
390 m1 = a * c
391 m2 = b * s
392 self.matrix[0] = m1 - m2
393 m1 = a * s
394 m2 = b * c
395 self.matrix[1] = m1 + m2
396 a = self.matrix[3]
397 b = self.matrix[4]
398 m1 = a * c
399 m2 = b * s
400 self.matrix[3] = m1 - m2
401 m1 = a * s
402 m2 = b * c
403 self.matrix[4] = m1 + m2
404
405
406 - def saveContext(self):
407 self.contextStack.append(self.context)
408 self.context = VMLContext(self.context)
409 self.matrix = self.context.matrix
410
411
413 self.context.arcScaleX *= x
414 self.context.arcScaleY *= y
415 self.matrix[0] *= x
416 self.matrix[1] *= y
417 self.matrix[3] *= x
418 self.matrix[4] *= y
419
420
423
424
428
429
433
434
436 self.currentX = currentX
437
438
440 self.currentY = currentY
441
442
444 self.context.fillGradient = gradient
445
446
448 fillStyle = str(fillStyle).strip()
449 if fillStyle.startswith("rgba("):
450 end = fillStyle.find(")", 12)
451 if end > -1:
452 guts = fillStyle[5:end].split(",")
453 if len(guts) == 4:
454 self.context.fillAlpha = float(guts[3])
455 self.context.fillStyle = "rgb(" + guts[0] + "," + guts[1] + "," + guts[2] + ")"
456
457
458 else:
459 self.context.fillAlpha = 1
460 self.context.fillStyle = fillStyle
461
462
463
465 self.context.globalAlpha = globalAlpha
466
467
474
475
476
478 if lineCap.strip().lower == GWTCanvasConsts.BUTT:
479 self.context.lineCap = BUTT
480 else:
481 self.context.lineCap = lineCap
482
483
484
486 self.context.lineJoin = lineJoin
487
488
490 self.context.lineWidth = lineWidth
491
492
494 self.context.miterLimit = miterLimit
495
497 self.parentElement = g
498
499
503
504
508
509
511 self.context.strokeGradient = gradient
512
513
515 strokeStyle = str(strokeStyle).strip()
516 if strokeStyle.startswith("rgba("):
517 end = strokeStyle.find(")", 12)
518 if end > -1:
519 guts = strokeStyle[5:end].split(",")
520 if len(guts) == 4:
521 self.context.strokeAlpha = float(guts[3])
522 self.context.strokeStyle = "rgb(" + guts[0] + "," + guts[1] + "," + guts[2] + ")"
523
524
525 else:
526 self.context.strokeAlpha = 1
527 self.context.strokeStyle = strokeStyle
528
529
530
532 if len(self.pathStr) == 0:
533 return
534
535 shapeStr = []
536 shapeStr.append("<v:shape style=\"position:absolute;width:10;height:10;\" coordsize=\"100,100\" filled=\"f\" strokecolor=\"")
537 shapeStr.append(str(self.context.strokeStyle))
538 shapeStr.append("\" strokeweight=\"")
539 shapeStr.append(str(self.context.lineWidth))
540 shapeStr.append("px\" path=\"")
541
542 shapeStr.append(self.pathStr.join())
543
544 shapeStr.append(" e\"><v:stroke opacity=\"")
545 shapeStr.append(str(self.context.globalAlpha * self.context.strokeAlpha))
546 shapeStr.append("\" miterlimit=\"")
547 shapeStr.append(str(self.context.miterLimit))
548 shapeStr.append("\" joinstyle=\"")
549 shapeStr.append(self.context.lineJoin)
550 shapeStr.append("\" endcap=\"")
551 shapeStr.append(self.context.lineCap)
552
553 shapeStr.append("\"></v:stroke></v:shape>")
554 self.insert(self.context.globalCompositeOperation, ''.join(shapeStr))
555
556
568
569
581
582
584 self.matrix[2] += self.matrix[0] * x + self.matrix[1] * y
585 self.matrix[5] += self.matrix[3] * x + self.matrix[4] * y
586
587
589 self.parentElement.insertAdjacentHTML(gco, html)
590