1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | #include "HTML5DrawingEngine.h" |
11 | #include "CanvasMessage.h" |
12 | |
13 | #include "BitmapDrawingEngine.h" |
14 | #include "DrawState.h" |
15 | |
16 | #include <Bitmap.h> |
17 | #include <utf8_functions.h> |
18 | |
19 | #include <new> |
20 | |
21 | |
22 | HTML5DrawingEngine::HTML5DrawingEngine(HTML5HWInterface* interface) |
23 | : |
24 | DrawingEngine(interface), |
25 | fHWInterface(interface), |
26 | fToken((uint32)this), |
27 | fExtendWidth(0), |
28 | fCallbackAdded(false), |
29 | fResultNotify(-1), |
30 | fStringWidthResult(0.0f), |
31 | fReadBitmapResult(NULL__null), |
32 | fBitmapDrawingEngine(NULL__null) |
33 | { |
34 | CanvasMessage message(NULL__null, fHWInterface->SendBuffer()); |
35 | message.Start(RP_CREATE_STATE); |
36 | message.Add(fToken); |
37 | } |
38 | |
39 | |
40 | HTML5DrawingEngine::~HTML5DrawingEngine() |
41 | { |
42 | CanvasMessage message(NULL__null, fHWInterface->SendBuffer()); |
43 | message.Start(RP_DELETE_STATE); |
44 | message.Add(fToken); |
45 | message.Flush(); |
46 | |
47 | delete fBitmapDrawingEngine; |
48 | |
49 | if (fCallbackAdded) |
50 | fHWInterface->RemoveCallback(fToken); |
51 | if (fResultNotify >= 0) |
52 | delete_sem(fResultNotify); |
53 | } |
54 | |
55 | |
56 | |
57 | |
58 | |
59 | void |
60 | HTML5DrawingEngine::FrameBufferChanged() |
61 | { |
62 | |
63 | } |
64 | |
65 | |
66 | |
67 | |
68 | |
69 | void |
70 | HTML5DrawingEngine::SetCopyToFrontEnabled(bool enabled) |
71 | { |
72 | DrawingEngine::SetCopyToFrontEnabled(enabled); |
73 | |
74 | CanvasMessage message(NULL__null, fHWInterface->SendBuffer()); |
75 | message.Start(enabled ? RP_ENABLE_SYNC_DRAWING : RP_DISABLE_SYNC_DRAWING); |
76 | message.Add(fToken); |
77 | } |
78 | |
79 | |
80 | |
81 | |
82 | |
83 | |
84 | void |
85 | HTML5DrawingEngine::ConstrainClippingRegion(const BRegion* region) |
86 | { |
87 | if (fClippingRegion == *region) |
88 | return; |
89 | |
90 | fClippingRegion = *region; |
91 | |
92 | CanvasMessage message(NULL__null, fHWInterface->SendBuffer()); |
93 | message.Start(RP_CONSTRAIN_CLIPPING_REGION); |
94 | message.Add(fToken); |
95 | message.AddRegion(*region); |
96 | } |
97 | |
98 | |
99 | void |
100 | HTML5DrawingEngine::SetDrawState(const DrawState* state, int32 xOffset, |
101 | int32 yOffset) |
102 | { |
103 | SetPenSize(state->PenSize()); |
104 | SetDrawingMode(state->GetDrawingMode()); |
105 | SetBlendingMode(state->AlphaSrcMode(), state->AlphaFncMode()); |
106 | SetPattern(state->GetPattern().GetPattern()); |
107 | SetStrokeMode(state->LineCapMode(), state->LineJoinMode(), |
108 | state->MiterLimit()); |
109 | SetHighColor(state->HighColor()); |
110 | SetLowColor(state->LowColor()); |
111 | SetFont(state->Font()); |
112 | |
113 | CanvasMessage message(NULL__null, fHWInterface->SendBuffer()); |
114 | message.Start(RP_SET_OFFSETS); |
115 | message.Add(fToken); |
116 | message.Add(xOffset); |
117 | message.Add(yOffset); |
118 | } |
119 | |
120 | |
121 | void |
122 | HTML5DrawingEngine::SetHighColor(const rgb_color& color) |
123 | { |
124 | if (fState.HighColor() == color) |
125 | return; |
126 | |
127 | fState.SetHighColor(color); |
128 | |
129 | CanvasMessage message(NULL__null, fHWInterface->SendBuffer()); |
130 | message.Start(RP_SET_HIGH_COLOR); |
131 | message.Add(fToken); |
132 | message.Add(color); |
133 | } |
134 | |
135 | |
136 | void |
137 | HTML5DrawingEngine::SetLowColor(const rgb_color& color) |
138 | { |
139 | if (fState.LowColor() == color) |
140 | return; |
141 | |
142 | fState.SetLowColor(color); |
143 | |
144 | CanvasMessage message(NULL__null, fHWInterface->SendBuffer()); |
145 | message.Start(RP_SET_LOW_COLOR); |
146 | message.Add(fToken); |
147 | message.Add(color); |
148 | } |
149 | |
150 | |
151 | void |
152 | HTML5DrawingEngine::SetPenSize(float size) |
153 | { |
154 | if (fState.PenSize() == size) |
155 | return; |
156 | |
157 | fState.SetPenSize(size); |
158 | fExtendWidth = -(size / 2); |
159 | |
160 | CanvasMessage message(NULL__null, fHWInterface->SendBuffer()); |
161 | message.Start(RP_SET_PEN_SIZE); |
162 | message.Add(fToken); |
163 | message.Add(size); |
164 | } |
165 | |
166 | |
167 | void |
168 | HTML5DrawingEngine::SetStrokeMode(cap_mode lineCap, join_mode joinMode, |
169 | float miterLimit) |
170 | { |
171 | if (fState.LineCapMode() == lineCap && fState.LineJoinMode() == joinMode |
172 | && fState.MiterLimit() == miterLimit) |
173 | return; |
174 | |
175 | fState.SetLineCapMode(lineCap); |
176 | fState.SetLineJoinMode(joinMode); |
177 | fState.SetMiterLimit(miterLimit); |
178 | |
179 | CanvasMessage message(NULL__null, fHWInterface->SendBuffer()); |
180 | message.Start(RP_SET_STROKE_MODE); |
181 | message.Add(fToken); |
182 | message.Add(lineCap); |
183 | message.Add(joinMode); |
184 | message.Add(miterLimit); |
185 | } |
186 | |
187 | |
188 | void |
189 | HTML5DrawingEngine::SetBlendingMode(source_alpha sourceAlpha, |
190 | alpha_function alphaFunc) |
191 | { |
192 | if (fState.AlphaSrcMode() == sourceAlpha |
193 | && fState.AlphaFncMode() == alphaFunc) |
194 | return; |
195 | |
196 | fState.SetBlendingMode(sourceAlpha, alphaFunc); |
197 | |
198 | CanvasMessage message(NULL__null, fHWInterface->SendBuffer()); |
199 | message.Start(RP_SET_BLENDING_MODE); |
200 | message.Add(fToken); |
201 | message.Add(sourceAlpha); |
202 | message.Add(alphaFunc); |
203 | } |
204 | |
205 | |
206 | void |
207 | HTML5DrawingEngine::SetPattern(const struct pattern& pattern) |
208 | { |
209 | if (fState.GetPattern() == pattern) |
210 | return; |
211 | |
212 | fState.SetPattern(pattern); |
213 | |
214 | CanvasMessage message(NULL__null, fHWInterface->SendBuffer()); |
215 | message.Start(RP_SET_PATTERN); |
216 | message.Add(fToken); |
217 | message.Add(pattern); |
218 | } |
219 | |
220 | |
221 | void |
222 | HTML5DrawingEngine::SetDrawingMode(drawing_mode mode) |
223 | { |
224 | if (fState.GetDrawingMode() == mode) |
225 | return; |
226 | |
227 | fState.SetDrawingMode(mode); |
228 | |
229 | CanvasMessage message(NULL__null, fHWInterface->SendBuffer()); |
230 | message.Start(RP_SET_DRAWING_MODE); |
231 | message.Add(fToken); |
232 | message.Add(mode); |
233 | } |
234 | |
235 | |
236 | void |
237 | HTML5DrawingEngine::SetDrawingMode(drawing_mode mode, drawing_mode& oldMode) |
238 | { |
239 | oldMode = fState.GetDrawingMode(); |
240 | SetDrawingMode(mode); |
241 | } |
242 | |
243 | |
244 | void |
245 | HTML5DrawingEngine::SetFont(const ServerFont& font) |
246 | { |
247 | if (fState.Font() == font) |
248 | return; |
249 | |
250 | fState.SetFont(font); |
251 | |
252 | CanvasMessage message(NULL__null, fHWInterface->SendBuffer()); |
253 | message.Start(RP_SET_FONT); |
254 | message.Add(fToken); |
255 | message.AddFont(font); |
256 | } |
257 | |
258 | |
259 | void |
260 | HTML5DrawingEngine::SetFont(const DrawState* state) |
261 | { |
262 | SetFont(state->Font()); |
263 | } |
264 | |
265 | |
266 | |
267 | |
268 | |
269 | BRect |
270 | HTML5DrawingEngine::CopyRect(BRect rect, int32 xOffset, int32 yOffset) const |
271 | { |
272 | CanvasMessage message(NULL__null, fHWInterface->SendBuffer()); |
273 | message.Start(RP_COPY_RECT_NO_CLIPPING); |
274 | message.Add(xOffset); |
275 | message.Add(yOffset); |
276 | message.Add(rect); |
277 | return rect.OffsetBySelf(xOffset, yOffset); |
278 | } |
279 | |
280 | |
281 | void |
282 | HTML5DrawingEngine::InvertRect(BRect rect) |
283 | { |
284 | if (!fClippingRegion.Intersects(rect)) |
285 | return; |
286 | |
287 | CanvasMessage message(NULL__null, fHWInterface->SendBuffer()); |
288 | message.Start(RP_INVERT_RECT); |
289 | message.Add(fToken); |
290 | message.Add(rect); |
291 | } |
292 | |
293 | |
294 | void |
295 | HTML5DrawingEngine::DrawBitmap(ServerBitmap* bitmap, const BRect& _bitmapRect, |
296 | const BRect& _viewRect, uint32 options) |
297 | { |
298 | BRect bitmapRect = _bitmapRect; |
299 | BRect viewRect = _viewRect; |
300 | double xScale = (bitmapRect.Width() + 1) / (viewRect.Width() + 1); |
301 | double yScale = (bitmapRect.Height() + 1) / (viewRect.Height() + 1); |
302 | |
303 | |
304 | |
305 | BRect actualBitmapRect = bitmap->Bounds(); |
306 | if (bitmapRect.left < actualBitmapRect.left) { |
307 | float diff = actualBitmapRect.left - bitmapRect.left; |
308 | viewRect.left += diff / xScale; |
309 | bitmapRect.left = actualBitmapRect.left; |
310 | } |
311 | if (bitmapRect.top < actualBitmapRect.top) { |
312 | float diff = actualBitmapRect.top - bitmapRect.top; |
313 | viewRect.top += diff / yScale; |
314 | bitmapRect.top = actualBitmapRect.top; |
315 | } |
316 | if (bitmapRect.right > actualBitmapRect.right) { |
317 | float diff = bitmapRect.right - actualBitmapRect.right; |
318 | viewRect.right -= diff / xScale; |
319 | bitmapRect.right = actualBitmapRect.right; |
320 | } |
321 | if (bitmapRect.bottom > actualBitmapRect.bottom) { |
322 | float diff = bitmapRect.bottom - actualBitmapRect.bottom; |
323 | viewRect.bottom -= diff / yScale; |
324 | bitmapRect.bottom = actualBitmapRect.bottom; |
325 | } |
326 | |
327 | BRegion clippedRegion(viewRect); |
328 | clippedRegion.IntersectWith(&fClippingRegion); |
329 | |
330 | int32 rectCount = clippedRegion.CountRects(); |
331 | if (rectCount == 0) |
332 | return; |
333 | |
334 | if (rectCount > 1 || (rectCount == 1 && clippedRegion.RectAt(0) != viewRect) |
335 | || viewRect.Width() < bitmapRect.Width() |
336 | || viewRect.Height() < bitmapRect.Height()) { |
337 | UtilityBitmap** bitmaps; |
338 | if (_ExtractBitmapRegions(*bitmap, options, bitmapRect, viewRect, |
339 | xScale, yScale, clippedRegion, bitmaps) != B_OK((int)0)) { |
340 | return; |
341 | } |
342 | |
343 | CanvasMessage message(NULL__null, fHWInterface->SendBuffer()); |
344 | message.Start(RP_DRAW_BITMAP_RECTS); |
345 | message.Add(fToken); |
346 | message.Add(options); |
347 | message.Add(bitmap->ColorSpace()); |
348 | message.Add(bitmap->Flags()); |
349 | message.Add(rectCount); |
350 | |
351 | for (int32 i = 0; i < rectCount; i++) { |
352 | message.Add(clippedRegion.RectAt(i)); |
353 | message.AddBitmap(*bitmaps[i], true); |
354 | delete bitmaps[i]; |
355 | } |
356 | |
357 | free(bitmaps); |
358 | return; |
359 | } |
360 | |
361 | |
362 | CanvasMessage message(NULL__null, fHWInterface->SendBuffer()); |
363 | message.Start(RP_DRAW_BITMAP); |
364 | message.Add(fToken); |
365 | message.Add(bitmapRect); |
366 | message.Add(viewRect); |
367 | message.Add(options); |
368 | message.AddBitmap(*bitmap); |
369 | } |
370 | |
371 | |
372 | void |
373 | HTML5DrawingEngine::DrawArc(BRect rect, const float& angle, const float& span, |
374 | bool filled) |
375 | { |
376 | BRect bounds = rect; |
377 | if (!filled) |
378 | bounds.InsetBy(fExtendWidth, fExtendWidth); |
379 | |
380 | if (!fClippingRegion.Intersects(bounds)) |
381 | return; |
382 | |
383 | CanvasMessage message(NULL__null, fHWInterface->SendBuffer()); |
384 | message.Start(filled ? RP_FILL_ARC : RP_STROKE_ARC); |
385 | message.Add(fToken); |
386 | message.Add(rect); |
387 | message.Add(angle); |
388 | message.Add(span); |
389 | } |
390 | |
391 | void |
392 | HTML5DrawingEngine::FillArc(BRect rect, const float& angle, const float& span, |
393 | const BGradient& gradient) |
394 | { |
395 | if (!fClippingRegion.Intersects(rect)) |
396 | return; |
397 | |
398 | CanvasMessage message(NULL__null, fHWInterface->SendBuffer()); |
399 | message.Start(RP_FILL_ARC_GRADIENT); |
400 | message.Add(fToken); |
401 | message.Add(rect); |
402 | message.Add(angle); |
403 | message.Add(span); |
404 | message.AddGradient(gradient); |
405 | } |
406 | |
407 | |
408 | void |
409 | HTML5DrawingEngine::DrawBezier(BPoint* points, bool filled) |
410 | { |
411 | BRect bounds = _BuildBounds(points, 4); |
412 | if (!filled) |
413 | bounds.InsetBy(fExtendWidth, fExtendWidth); |
414 | |
415 | if (!fClippingRegion.Intersects(bounds)) |
416 | return; |
417 | |
418 | CanvasMessage message(NULL__null, fHWInterface->SendBuffer()); |
419 | message.Start(filled ? RP_FILL_BEZIER : RP_STROKE_BEZIER); |
420 | message.Add(fToken); |
421 | message.AddList(points, 4); |
422 | } |
423 | |
424 | |
425 | void |
426 | HTML5DrawingEngine::FillBezier(BPoint* points, const BGradient& gradient) |
427 | { |
428 | BRect bounds = _BuildBounds(points, 4); |
429 | if (!fClippingRegion.Intersects(bounds)) |
430 | return; |
431 | |
432 | CanvasMessage message(NULL__null, fHWInterface->SendBuffer()); |
433 | message.Start(RP_FILL_BEZIER_GRADIENT); |
434 | message.Add(fToken); |
435 | message.AddList(points, 4); |
436 | message.AddGradient(gradient); |
437 | } |
438 | |
439 | |
440 | void |
441 | HTML5DrawingEngine::DrawEllipse(BRect rect, bool filled) |
442 | { |
443 | BRect bounds = rect; |
444 | if (!filled) |
445 | bounds.InsetBy(fExtendWidth, fExtendWidth); |
446 | |
447 | if (!fClippingRegion.Intersects(bounds)) |
448 | return; |
449 | |
450 | CanvasMessage message(NULL__null, fHWInterface->SendBuffer()); |
451 | message.Start(filled ? RP_FILL_ELLIPSE : RP_STROKE_ELLIPSE); |
452 | message.Add(fToken); |
453 | message.Add(rect); |
454 | } |
455 | |
456 | |
457 | void |
458 | HTML5DrawingEngine::FillEllipse(BRect rect, const BGradient& gradient) |
459 | { |
460 | if (!fClippingRegion.Intersects(rect)) |
461 | return; |
462 | |
463 | CanvasMessage message(NULL__null, fHWInterface->SendBuffer()); |
464 | message.Start(RP_FILL_ELLIPSE_GRADIENT); |
465 | message.Add(fToken); |
466 | message.Add(rect); |
467 | message.AddGradient(gradient); |
468 | } |
469 | |
470 | |
471 | void |
472 | HTML5DrawingEngine::DrawPolygon(BPoint* pointList, int32 numPoints, |
473 | BRect bounds, bool filled, bool closed) |
474 | { |
475 | BRect clipBounds = bounds; |
476 | if (!filled) |
477 | clipBounds.InsetBy(fExtendWidth, fExtendWidth); |
478 | |
479 | if (!fClippingRegion.Intersects(clipBounds)) |
480 | return; |
481 | |
482 | CanvasMessage message(NULL__null, fHWInterface->SendBuffer()); |
483 | message.Start(filled ? RP_FILL_POLYGON : RP_STROKE_POLYGON); |
484 | message.Add(fToken); |
485 | message.Add(bounds); |
486 | message.Add(closed); |
487 | message.Add(numPoints); |
488 | for (int32 i = 0; i < numPoints; i++) |
489 | message.Add(pointList[i]); |
490 | } |
491 | |
492 | |
493 | void |
494 | HTML5DrawingEngine::FillPolygon(BPoint* pointList, int32 numPoints, |
495 | BRect bounds, const BGradient& gradient, bool closed) |
496 | { |
497 | if (!fClippingRegion.Intersects(bounds)) |
498 | return; |
499 | |
500 | CanvasMessage message(NULL__null, fHWInterface->SendBuffer()); |
501 | message.Start(RP_FILL_POLYGON_GRADIENT); |
502 | message.Add(fToken); |
503 | message.Add(bounds); |
504 | message.Add(closed); |
505 | message.Add(numPoints); |
506 | for (int32 i = 0; i < numPoints; i++) |
507 | message.Add(pointList[i]); |
508 | message.AddGradient(gradient); |
509 | } |
510 | |
511 | |
512 | |
513 | |
514 | |
515 | void |
516 | HTML5DrawingEngine::StrokePoint(const BPoint& point, const rgb_color& color) |
517 | { |
518 | BRect bounds(point, point); |
519 | bounds.InsetBy(fExtendWidth, fExtendWidth); |
520 | |
521 | if (!fClippingRegion.Intersects(bounds)) |
522 | return; |
523 | |
524 | CanvasMessage message(NULL__null, fHWInterface->SendBuffer()); |
525 | message.Start(RP_STROKE_POINT_COLOR); |
526 | message.Add(fToken); |
527 | message.Add(point); |
528 | message.Add(color); |
529 | } |
530 | |
531 | |
532 | void |
533 | HTML5DrawingEngine::StrokeLine(const BPoint& start, const BPoint& end, |
534 | const rgb_color& color) |
535 | { |
536 | BPoint points[2] = { start, end }; |
537 | BRect bounds = _BuildBounds(points, 2); |
538 | |
539 | if (!fClippingRegion.Intersects(bounds)) |
540 | return; |
541 | |
542 | CanvasMessage message(NULL__null, fHWInterface->SendBuffer()); |
543 | message.Start(RP_STROKE_LINE_1PX_COLOR); |
544 | message.Add(fToken); |
545 | message.AddList(points, 2); |
546 | message.Add(color); |
547 | } |
548 | |
549 | |
550 | void |
551 | HTML5DrawingEngine::StrokeRect(BRect rect, const rgb_color &color) |
552 | { |
553 | BRect bounds = rect; |
554 | bounds.InsetBy(fExtendWidth, fExtendWidth); |
555 | |
556 | if (!fClippingRegion.Intersects(bounds)) |
557 | return; |
558 | |
559 | CanvasMessage message(NULL__null, fHWInterface->SendBuffer()); |
560 | message.Start(RP_STROKE_RECT_1PX_COLOR); |
561 | message.Add(fToken); |
562 | message.Add(rect); |
563 | message.Add(color); |
564 | } |
565 | |
566 | |
567 | void |
568 | HTML5DrawingEngine::FillRect(BRect rect, const rgb_color& color) |
569 | { |
570 | if (!fClippingRegion.Intersects(rect)) |
571 | return; |
572 | |
573 | CanvasMessage message(NULL__null, fHWInterface->SendBuffer()); |
574 | message.Start(RP_FILL_RECT_COLOR); |
575 | message.Add(fToken); |
576 | message.Add(rect); |
577 | message.Add(color); |
578 | } |
579 | |
580 | |
581 | void |
582 | HTML5DrawingEngine::FillRegion(BRegion& region, const rgb_color& color) |
583 | { |
584 | CanvasMessage message(NULL__null, fHWInterface->SendBuffer()); |
585 | message.Start(RP_FILL_REGION_COLOR_NO_CLIPPING); |
586 | message.AddRegion(region); |
587 | message.Add(color); |
588 | } |
589 | |
590 | |
591 | |
592 | |
593 | |
594 | void |
595 | HTML5DrawingEngine::StrokeRect(BRect rect) |
596 | { |
597 | BRect bounds = rect; |
598 | bounds.InsetBy(fExtendWidth, fExtendWidth); |
599 | |
600 | if (!fClippingRegion.Intersects(bounds)) |
601 | return; |
602 | |
603 | CanvasMessage message(NULL__null, fHWInterface->SendBuffer()); |
604 | message.Start(RP_STROKE_RECT); |
605 | message.Add(fToken); |
606 | message.Add(rect); |
607 | } |
608 | |
609 | |
610 | void |
611 | HTML5DrawingEngine::FillRect(BRect rect) |
612 | { |
613 | if (!fClippingRegion.Intersects(rect)) |
614 | return; |
615 | |
616 | CanvasMessage message(NULL__null, fHWInterface->SendBuffer()); |
617 | message.Start(RP_FILL_RECT); |
618 | message.Add(fToken); |
619 | message.Add(rect); |
620 | } |
621 | |
622 | |
623 | void |
624 | HTML5DrawingEngine::FillRect(BRect rect, const BGradient& gradient) |
625 | { |
626 | if (!fClippingRegion.Intersects(rect)) |
627 | return; |
628 | |
629 | CanvasMessage message(NULL__null, fHWInterface->SendBuffer()); |
630 | message.Start(RP_FILL_RECT_GRADIENT); |
631 | message.Add(fToken); |
632 | message.Add(rect); |
633 | message.AddGradient(gradient); |
634 | } |
635 | |
636 | |
637 | void |
638 | HTML5DrawingEngine::FillRegion(BRegion& region) |
639 | { |
640 | BRegion clippedRegion = region; |
641 | clippedRegion.IntersectWith(&fClippingRegion); |
642 | if (clippedRegion.CountRects() == 0) |
643 | return; |
644 | |
645 | CanvasMessage message(NULL__null, fHWInterface->SendBuffer()); |
646 | message.Start(RP_FILL_REGION); |
647 | message.Add(fToken); |
648 | message.AddRegion(clippedRegion.CountRects() < region.CountRects() |
649 | ? clippedRegion : region); |
650 | } |
651 | |
652 | |
653 | void |
654 | HTML5DrawingEngine::FillRegion(BRegion& region, const BGradient& gradient) |
655 | { |
656 | BRegion clippedRegion = region; |
657 | clippedRegion.IntersectWith(&fClippingRegion); |
658 | if (clippedRegion.CountRects() == 0) |
659 | return; |
660 | |
661 | CanvasMessage message(NULL__null, fHWInterface->SendBuffer()); |
662 | message.Start(RP_FILL_REGION_GRADIENT); |
663 | message.Add(fToken); |
664 | message.AddRegion(clippedRegion.CountRects() < region.CountRects() |
665 | ? clippedRegion : region); |
666 | message.AddGradient(gradient); |
667 | } |
668 | |
669 | |
670 | void |
671 | HTML5DrawingEngine::DrawRoundRect(BRect rect, float xRadius, float yRadius, |
672 | bool filled) |
673 | { |
674 | BRect bounds = rect; |
675 | if (!filled) |
676 | bounds.InsetBy(fExtendWidth, fExtendWidth); |
677 | |
678 | if (!fClippingRegion.Intersects(bounds)) |
679 | return; |
680 | |
681 | CanvasMessage message(NULL__null, fHWInterface->SendBuffer()); |
682 | message.Start(filled ? RP_FILL_ROUND_RECT : RP_STROKE_ROUND_RECT); |
683 | message.Add(fToken); |
684 | message.Add(rect); |
685 | message.Add(xRadius); |
686 | message.Add(yRadius); |
687 | } |
688 | |
689 | |
690 | void |
691 | HTML5DrawingEngine::FillRoundRect(BRect rect, float xRadius, float yRadius, |
692 | const BGradient& gradient) |
693 | { |
694 | if (!fClippingRegion.Intersects(rect)) |
695 | return; |
696 | |
697 | CanvasMessage message(NULL__null, fHWInterface->SendBuffer()); |
698 | message.Start(RP_FILL_ROUND_RECT_GRADIENT); |
699 | message.Add(fToken); |
700 | message.Add(rect); |
701 | message.Add(xRadius); |
702 | message.Add(yRadius); |
703 | message.AddGradient(gradient); |
704 | } |
705 | |
706 | |
707 | void |
708 | HTML5DrawingEngine::DrawShape(const BRect& bounds, int32 opCount, |
709 | const uint32* opList, int32 pointCount, const BPoint* pointList, |
710 | bool filled, const BPoint& viewToScreenOffset, float viewScale) |
711 | { |
712 | BRect clipBounds = bounds; |
713 | if (!filled) |
714 | clipBounds.InsetBy(fExtendWidth, fExtendWidth); |
715 | |
716 | if (!fClippingRegion.Intersects(clipBounds)) |
717 | return; |
718 | |
719 | CanvasMessage message(NULL__null, fHWInterface->SendBuffer()); |
720 | message.Start(filled ? RP_FILL_SHAPE : RP_STROKE_SHAPE); |
721 | message.Add(fToken); |
722 | message.Add(bounds); |
723 | message.Add(opCount); |
724 | message.AddList(opList, opCount); |
725 | message.Add(pointCount); |
726 | message.AddList(pointList, pointCount); |
727 | message.Add(viewToScreenOffset); |
728 | message.Add(viewScale); |
729 | } |
730 | |
731 | |
732 | void |
733 | HTML5DrawingEngine::FillShape(const BRect& bounds, int32 opCount, |
734 | const uint32* opList, int32 pointCount, const BPoint* pointList, |
735 | const BGradient& gradient, const BPoint& viewToScreenOffset, |
736 | float viewScale) |
737 | { |
738 | if (!fClippingRegion.Intersects(bounds)) |
739 | return; |
740 | |
741 | CanvasMessage message(NULL__null, fHWInterface->SendBuffer()); |
742 | message.Start(RP_FILL_SHAPE_GRADIENT); |
743 | message.Add(fToken); |
744 | message.Add(bounds); |
745 | message.Add(opCount); |
746 | message.AddList(opList, opCount); |
747 | message.Add(pointCount); |
748 | message.AddList(pointList, pointCount); |
749 | message.AddGradient(gradient); |
750 | message.Add(viewToScreenOffset); |
751 | message.Add(viewScale); |
752 | } |
753 | |
754 | |
755 | void |
756 | HTML5DrawingEngine::DrawTriangle(BPoint* points, const BRect& bounds, |
757 | bool filled) |
758 | { |
759 | BRect clipBounds = bounds; |
760 | if (!filled) |
761 | clipBounds.InsetBy(fExtendWidth, fExtendWidth); |
762 | |
763 | if (!fClippingRegion.Intersects(clipBounds)) |
764 | return; |
765 | |
766 | CanvasMessage message(NULL__null, fHWInterface->SendBuffer()); |
767 | message.Start(filled ? RP_FILL_TRIANGLE : RP_STROKE_TRIANGLE); |
768 | message.Add(fToken); |
769 | message.AddList(points, 3); |
770 | message.Add(bounds); |
771 | } |
772 | |
773 | |
774 | void |
775 | HTML5DrawingEngine::FillTriangle(BPoint* points, const BRect& bounds, |
776 | const BGradient& gradient) |
777 | { |
778 | if (!fClippingRegion.Intersects(bounds)) |
779 | return; |
780 | |
781 | CanvasMessage message(NULL__null, fHWInterface->SendBuffer()); |
782 | message.Start(RP_FILL_TRIANGLE_GRADIENT); |
783 | message.Add(fToken); |
784 | message.Add(points[0]); |
785 | message.Add(points[1]); |
786 | message.Add(points[2]); |
787 | message.Add(bounds); |
788 | message.AddGradient(gradient); |
789 | } |
790 | |
791 | |
792 | void |
793 | HTML5DrawingEngine::StrokeLine(const BPoint &start, const BPoint &end) |
794 | { |
795 | BPoint points[2] = { start, end }; |
796 | BRect bounds = _BuildBounds(points, 2); |
797 | |
798 | if (!fClippingRegion.Intersects(bounds)) |
799 | return; |
800 | |
801 | CanvasMessage message(NULL__null, fHWInterface->SendBuffer()); |
802 | message.Start(RP_STROKE_LINE); |
803 | message.Add(fToken); |
804 | message.AddList(points, 2); |
805 | } |
806 | |
807 | |
808 | void |
809 | HTML5DrawingEngine::StrokeLineArray(int32 numLines, |
810 | const ViewLineArrayInfo *lineData) |
811 | { |
812 | CanvasMessage message(NULL__null, fHWInterface->SendBuffer()); |
813 | message.Start(RP_STROKE_LINE_ARRAY); |
814 | message.Add(fToken); |
815 | message.Add(numLines); |
816 | for (int32 i = 0; i < numLines; i++) |
817 | message.AddArrayLine(lineData[i]); |
818 | } |
819 | |
820 | |
821 | |
822 | |
823 | |
824 | BPoint |
825 | HTML5DrawingEngine::DrawString(const char* string, int32 length, |
826 | const BPoint& point, escapement_delta* delta) |
827 | { |
828 | CanvasMessage message(NULL__null, fHWInterface->SendBuffer()); |
829 | |
830 | message.Start(RP_DRAW_STRING); |
831 | message.Add(fToken); |
832 | message.Add(point); |
833 | message.AddString(string, length); |
834 | message.Add(delta != NULL__null); |
835 | if (delta != NULL__null) |
836 | message.AddList(delta, length); |
837 | |
838 | status_t result = _AddCallback(); |
839 | if (message.Flush() != B_OK((int)0)) |
840 | return point; |
841 | |
842 | if (result != B_OK((int)0)) |
843 | return point; |
844 | |
845 | do { |
846 | result = acquire_sem_etc(fResultNotify, 1, B_RELATIVE_TIMEOUT, |
847 | 1 * 1000 * 1000); |
848 | } while (result == B_INTERRUPTED((-2147483647 - 1) + 10)); |
849 | |
850 | if (result != B_OK((int)0)) |
851 | return point; |
852 | |
853 | return fDrawStringResult; |
854 | } |
855 | |
856 | |
857 | BPoint |
858 | HTML5DrawingEngine::DrawString(const char* string, int32 length, |
859 | const BPoint* offsets) |
860 | { |
861 | |
862 | CanvasMessage message(NULL__null, fHWInterface->SendBuffer()); |
863 | |
864 | message.Start(RP_DRAW_STRING_WITH_OFFSETS); |
865 | message.Add(fToken); |
866 | message.AddString(string, length); |
867 | message.AddList(offsets, UTF8CountChars(string, length)); |
868 | |
869 | status_t result = _AddCallback(); |
870 | if (message.Flush() != B_OK((int)0)) |
871 | return offsets[0]; |
872 | |
873 | if (result != B_OK((int)0)) |
874 | return offsets[0]; |
875 | |
876 | do { |
877 | result = acquire_sem_etc(fResultNotify, 1, B_RELATIVE_TIMEOUT, |
878 | 1 * 1000 * 1000); |
879 | } while (result == B_INTERRUPTED((-2147483647 - 1) + 10)); |
880 | |
881 | if (result != B_OK((int)0)) |
882 | return offsets[0]; |
883 | |
884 | return fDrawStringResult; |
885 | } |
886 | |
887 | |
888 | float |
889 | HTML5DrawingEngine::StringWidth(const char* string, int32 length, |
890 | escapement_delta* delta) |
891 | { |
892 | |
893 | return fState.Font().StringWidth(string, length, delta); |
894 | } |
895 | |
896 | |
897 | |
898 | |
899 | |
900 | status_t |
901 | HTML5DrawingEngine::ReadBitmap(ServerBitmap* bitmap, bool drawCursor, |
902 | BRect bounds) |
903 | { |
904 | if (_AddCallback() != B_OK((int)0)) |
905 | return B_UNSUPPORTED(((-2147483647 - 1) + 0x6000) + 14); |
906 | |
907 | CanvasMessage message(NULL__null, fHWInterface->SendBuffer()); |
908 | |
909 | message.Start(RP_READ_BITMAP); |
910 | message.Add(fToken); |
911 | message.Add(bounds); |
912 | message.Add(drawCursor); |
913 | if (message.Flush() != B_OK((int)0)) |
914 | return B_UNSUPPORTED(((-2147483647 - 1) + 0x6000) + 14); |
915 | |
916 | status_t result; |
917 | do { |
918 | result = acquire_sem_etc(fResultNotify, 1, B_RELATIVE_TIMEOUT, |
919 | 100 * 1000 * 1000); |
920 | } while (result == B_INTERRUPTED((-2147483647 - 1) + 10)); |
921 | |
922 | if (result != B_OK((int)0)) |
923 | return result; |
924 | |
925 | BBitmap* read = fReadBitmapResult; |
926 | if (read == NULL__null) |
927 | return B_UNSUPPORTED(((-2147483647 - 1) + 0x6000) + 14); |
928 | |
929 | result = bitmap->ImportBits(read->Bits(), read->BitsLength(), |
930 | read->BytesPerRow(), read->ColorSpace()); |
931 | delete read; |
932 | return result; |
933 | } |
934 | |
935 | |
936 | |
937 | |
938 | |
939 | status_t |
940 | HTML5DrawingEngine::_AddCallback() |
941 | { |
942 | if (fCallbackAdded) |
943 | return B_OK((int)0); |
944 | |
945 | if (fResultNotify < 0) |
946 | fResultNotify = create_sem(0, "drawing engine result"); |
947 | if (fResultNotify < 0) |
948 | return fResultNotify; |
949 | |
950 | status_t result = fHWInterface->AddCallback(fToken, &_DrawingEngineResult, |
951 | this); |
952 | |
953 | fCallbackAdded = result == B_OK((int)0); |
954 | return result; |
955 | } |
956 | |
957 | |
958 | bool |
959 | HTML5DrawingEngine::_DrawingEngineResult(void* cookie, CanvasMessage& message) |
960 | { |
961 | HTML5DrawingEngine* engine = (HTML5DrawingEngine*)cookie; |
962 | |
963 | switch (message.Code()) { |
964 | case RP_DRAW_STRING_RESULT: |
965 | if (message.Read(engine->fDrawStringResult) != B_OK((int)0)) |
966 | return false; |
967 | break; |
968 | |
969 | case RP_STRING_WIDTH_RESULT: |
970 | if (message.Read(engine->fStringWidthResult) != B_OK((int)0)) |
971 | return false; |
972 | break; |
973 | |
974 | case RP_READ_BITMAP_RESULT: |
975 | if (message.ReadBitmap(&engine->fReadBitmapResult) != B_OK((int)0)) |
976 | return false; |
977 | break; |
978 | |
979 | default: |
980 | return false; |
981 | } |
982 | |
983 | release_sem(engine->fResultNotify); |
984 | return true; |
985 | } |
986 | |
987 | |
988 | BRect |
989 | HTML5DrawingEngine::_BuildBounds(BPoint* points, int32 pointCount) |
990 | { |
991 | BRect bounds(1000000, 1000000, 0, 0); |
992 | for (int32 i = 0; i < pointCount; i++) { |
993 | bounds.left = min_c(bounds.left, points[i].x)((bounds.left)>(points[i].x)?(points[i].x):(bounds.left)); |
994 | bounds.top = min_c(bounds.top, points[i].y)((bounds.top)>(points[i].y)?(points[i].y):(bounds.top)); |
995 | bounds.right = max_c(bounds.right, points[i].x)((bounds.right)>(points[i].x)?(bounds.right):(points[i].x) ); |
996 | bounds.bottom = max_c(bounds.bottom, points[i].y)((bounds.bottom)>(points[i].y)?(bounds.bottom):(points[i]. y)); |
997 | } |
998 | |
999 | return bounds; |
1000 | } |
1001 | |
1002 | |
1003 | status_t |
1004 | HTML5DrawingEngine::_ExtractBitmapRegions(ServerBitmap& bitmap, uint32 options, |
1005 | const BRect& bitmapRect, const BRect& viewRect, double xScale, |
1006 | double yScale, BRegion& region, UtilityBitmap**& bitmaps) |
1007 | { |
1008 | int32 rectCount = region.CountRects(); |
1009 | bitmaps = (UtilityBitmap**)malloc(rectCount * sizeof(UtilityBitmap*)); |
1010 | if (bitmaps == NULL__null) |
| |
1011 | return B_NO_MEMORY((-2147483647 - 1) + 0); |
1012 | |
1013 | for (int32 i = 0; i < rectCount; i++) { |
| 2 | | Assuming 'i' is < 'rectCount' | |
|
| 3 | | Loop condition is true. Entering loop body | |
|
| 10 | | Assuming 'i' is < 'rectCount' | |
|
| 11 | | Loop condition is true. Entering loop body | |
|
1014 | BRect sourceRect = region.RectAt(i).OffsetByCopy(-viewRect.LeftTop()); |
1015 | int32 targetWidth = (int32)(sourceRect.Width() + 1.5); |
1016 | int32 targetHeight = (int32)(sourceRect.Height() + 1.5); |
1017 | |
1018 | if (xScale != 1.0) { |
| |
| |
1019 | sourceRect.left = (int32)(sourceRect.left * xScale + 0.5); |
1020 | sourceRect.right = (int32)(sourceRect.right * xScale + 0.5); |
1021 | if (xScale < 1.0) |
1022 | targetWidth = (int32)(sourceRect.Width() + 1.5); |
1023 | } |
1024 | |
1025 | if (yScale != 1.0) { |
| |
| |
1026 | sourceRect.top = (int32)(sourceRect.top * yScale + 0.5); |
1027 | sourceRect.bottom = (int32)(sourceRect.bottom * yScale + 0.5); |
1028 | if (yScale < 1.0) |
1029 | targetHeight = (int32)(sourceRect.Height() + 1.5); |
1030 | } |
1031 | |
1032 | sourceRect.OffsetBy(bitmapRect.LeftTop()); |
1033 | |
1034 | |
1035 | status_t result = B_OK((int)0); |
1036 | if ((xScale > 1.0 || yScale > 1.0) |
1037 | && (targetWidth * targetHeight < (int32)(sourceRect.Width() + 1.5) |
1038 | * (int32)(sourceRect.Height() + 1.5))) { |
1039 | |
1040 | |
1041 | if (fBitmapDrawingEngine == NULL__null) { |
1042 | fBitmapDrawingEngine |
1043 | = new(std::nothrow) BitmapDrawingEngine(B_RGBA32); |
1044 | if (fBitmapDrawingEngine == NULL__null) |
1045 | result = B_NO_MEMORY((-2147483647 - 1) + 0); |
1046 | } |
1047 | |
1048 | if (result == B_OK((int)0)) { |
1049 | result = fBitmapDrawingEngine->SetSize(targetWidth, |
1050 | targetHeight); |
1051 | } |
1052 | |
1053 | if (result == B_OK((int)0)) { |
1054 | fBitmapDrawingEngine->SetDrawingMode(B_OP_COPY); |
1055 | |
1056 | switch (bitmap.ColorSpace()) { |
1057 | case B_RGBA32: |
1058 | case B_RGBA32_BIG: |
1059 | case B_RGBA15: |
1060 | case B_RGBA15_BIG: |
1061 | break; |
1062 | |
1063 | default: |
1064 | { |
1065 | |
1066 | |
1067 | |
1068 | |
1069 | |
1070 | |
1071 | |
1072 | |
1073 | rgb_color background = { 0, 0, 0, 0 }; |
1074 | fBitmapDrawingEngine->FillRect( |
1075 | BRect(0, 0, targetWidth - 1, targetHeight -1), |
1076 | background); |
1077 | fBitmapDrawingEngine->SetDrawingMode(B_OP_OVER); |
1078 | break; |
1079 | } |
1080 | } |
1081 | |
1082 | fBitmapDrawingEngine->DrawBitmap(&bitmap, sourceRect, |
1083 | BRect(0, 0, targetWidth - 1, targetHeight - 1), options); |
1084 | bitmaps[i] = fBitmapDrawingEngine->ExportToBitmap(targetWidth, |
1085 | targetHeight, bitmap.ColorSpace()); |
1086 | if (bitmaps[i] == NULL__null) |
1087 | result = B_NO_MEMORY((-2147483647 - 1) + 0); |
1088 | } |
1089 | } else { |
1090 | |
1091 | |
1092 | targetWidth = (int32)(sourceRect.Width() + 1.5); |
1093 | targetHeight = (int32)(sourceRect.Height() + 1.5); |
1094 | |
1095 | bitmaps[i] = new(std::nothrow) UtilityBitmap( |
1096 | BRect(0, 0, targetWidth - 1, targetHeight - 1), |
1097 | bitmap.ColorSpace(), 0); |
1098 | if (bitmaps[i] == NULL__null) |
| |
| |
1099 | result = B_NO_MEMORY((-2147483647 - 1) + 0); |
1100 | |
1101 | result = bitmaps[i]->ImportBits(bitmap.Bits(), bitmap.BitsLength(), |
| 15 | | Called C++ object pointer is null |
|
1102 | bitmap.BytesPerRow(), bitmap.ColorSpace(), sourceRect.LeftTop(), |
1103 | BPoint(0, 0), targetWidth, targetHeight); |
1104 | if (result != B_OK((int)0)) |
| 7 | | Assuming 'result' is equal to 0 | |
|
| |
1105 | delete bitmaps[i]; |
1106 | } |
1107 | |
1108 | if (result != B_OK((int)0)) { |
| |
1109 | for (int32 j = 0; j < i; j++) |
1110 | delete bitmaps[j]; |
1111 | free(bitmaps); |
1112 | return result; |
1113 | } |
1114 | } |
1115 | |
1116 | return B_OK((int)0); |
1117 | } |