vfs: check userland buffers before reading them.
[haiku.git] / src / servers / app / PictureBoundingBoxPlayer.cpp
blob0e465b8190964fc44e034d283cac22c8c69524de
1 /*
2 * Copyright 2001-2015, Haiku.
3 * Distributed under the terms of the MIT License.
5 * Authors:
6 * Marc Flerackers (mflerackers@androme.be)
7 * Stefano Ceccherini (stefano.ceccherini@gmail.com)
8 * Marcus Overhagen <marcus@overhagen.de>
9 * Julian Harnath <julian.harnath@rwth-aachen.de>
12 #include "PictureBoundingBoxPlayer.h"
14 #include <new>
15 #include <stdio.h>
17 #include "DrawState.h"
18 #include "FontManager.h"
19 #include "Layer.h"
20 #include "ServerApp.h"
21 #include "ServerBitmap.h"
22 #include "ServerFont.h"
23 #include "ServerPicture.h"
24 #include "ServerTokenSpace.h"
25 #include "View.h"
26 #include "Window.h"
28 #include <Bitmap.h>
29 #include <Debug.h>
30 #include <List.h>
31 #include <ObjectListPrivate.h>
32 #include <PicturePlayer.h>
33 #include <PictureProtocol.h>
34 #include <Shape.h>
37 //#define DEBUG_TRACE_BB
38 #ifdef DEBUG_TRACE_BB
39 # define TRACE_BB(text, ...) debug_printf("PBBP: " text, ##__VA_ARGS__)
40 #else
41 # define TRACE_BB(text, ...)
42 #endif
45 typedef PictureBoundingBoxPlayer::State BoundingBoxState;
48 // #pragma mark - PictureBoundingBoxPlayer::State
51 class PictureBoundingBoxPlayer::State {
52 public:
53 State(const DrawState* drawState, BRect* boundingBox)
55 fDrawState(drawState->Squash()),
56 fBoundingBox(boundingBox)
58 fBoundingBox->Set(INT_MAX, INT_MAX, INT_MIN, INT_MIN);
61 ~State()
63 delete fDrawState;
66 DrawState* GetDrawState()
68 return fDrawState;
71 void PushDrawState()
73 DrawState* nextState = fDrawState->PushState();
74 if (nextState != NULL)
75 fDrawState = nextState;
78 void PopDrawState()
80 if (fDrawState->PreviousState() != NULL)
81 fDrawState = fDrawState->PopState();
84 SimpleTransform PenToLocalTransform() const
86 SimpleTransform transform;
87 fDrawState->Transform(transform);
88 return transform;
91 void IncludeRect(BRect& rect)
93 _AffineTransformRect(rect);
94 *fBoundingBox = (*fBoundingBox) | rect;
97 private:
98 void _AffineTransformRect(BRect& rect)
100 BAffineTransform transform = fDrawState->CombinedTransform();
101 if (transform.IsIdentity())
102 return;
104 BPoint transformedShape[4];
105 transformedShape[0] = rect.LeftTop();
106 transformedShape[1] = rect.LeftBottom();
107 transformedShape[2] = rect.RightTop();
108 transformedShape[3] = rect.RightBottom();
110 transform.Apply(&transformedShape[0], 4);
112 float minX = INT_MAX;
113 float minY = INT_MAX;
114 float maxX = INT_MIN;
115 float maxY = INT_MIN;
117 for (uint32 i = 0; i < 4; i++) {
118 if (transformedShape[i].x < minX)
119 minX = transformedShape[i].x;
120 else if (transformedShape[i].x > maxX)
121 maxX = transformedShape[i].x;
122 if (transformedShape[i].y < minY)
123 minY = transformedShape[i].y;
124 else if (transformedShape[i].y > maxY)
125 maxY = transformedShape[i].y;
128 rect.Set(minX, minY, maxX, maxY);
132 private:
133 DrawState* fDrawState;
134 BRect* fBoundingBox;
138 // #pragma mark - Picture playback hooks
141 static void
142 get_polygon_frame(const BPoint* points, int32 numPoints, BRect* frame)
144 ASSERT(numPoints > 0);
146 float left = points->x;
147 float top = points->y;
148 float right = left;
149 float bottom = top;
151 points++;
152 numPoints--;
154 while (numPoints--) {
155 if (points->x < left)
156 left = points->x;
157 if (points->x > right)
158 right = points->x;
159 if (points->y < top)
160 top = points->y;
161 if (points->y > bottom)
162 bottom = points->y;
163 points++;
166 frame->Set(left, top, right, bottom);
170 template<class RectType>
171 static void
172 expand_rect_for_pen_size(BoundingBoxState* state, RectType& rect)
174 float penInset = -((state->GetDrawState()->PenSize() / 2.0f) + 1.0f);
175 rect.InsetBy(penInset, penInset);
179 static void
180 move_pen_by(void* _state, const BPoint& delta)
182 TRACE_BB("%p move pen by %.2f %.2f\n", _state, delta.x, delta.y);
183 BoundingBoxState* const state =
184 reinterpret_cast<BoundingBoxState*>(_state);
186 state->GetDrawState()->SetPenLocation(
187 state->GetDrawState()->PenLocation() + delta);
191 static void
192 determine_bounds_stroke_line(void* _state, const BPoint& _start,
193 const BPoint& _end)
195 TRACE_BB("%p stroke line %.2f %.2f -> %.2f %.2f\n", _state,
196 _start.x, _start.y, _end.x, _end.y);
197 BoundingBoxState* const state =
198 reinterpret_cast<BoundingBoxState*>(_state);
200 BPoint start = _start;
201 BPoint end = _end;
203 const SimpleTransform transform = state->PenToLocalTransform();
204 transform.Apply(&start);
205 transform.Apply(&end);
207 BRect rect;
208 if (start.x <= end.x) {
209 rect.left = start.x;
210 rect.right = end.x;
211 } else {
212 rect.left = end.x;
213 rect.right = start.x;
215 if (start.y <= end.y) {
216 rect.top = start.y;
217 rect.bottom = end.y;
218 } else {
219 rect.top = end.y;
220 rect.bottom = start.y;
223 expand_rect_for_pen_size(state, rect);
224 state->IncludeRect(rect);
226 state->GetDrawState()->SetPenLocation(_end);
230 static void
231 determine_bounds_draw_rect(void* _state, const BRect& _rect, bool fill)
233 TRACE_BB("%p draw rect fill=%d %.2f %.2f %.2f %.2f\n", _state, fill,
234 _rect.left, _rect.top, _rect.right, _rect.bottom);
235 BoundingBoxState* const state =
236 reinterpret_cast<BoundingBoxState*>(_state);
238 BRect rect = _rect;
239 state->PenToLocalTransform().Apply(&rect);
240 if (!fill)
241 expand_rect_for_pen_size(state, rect);
242 state->IncludeRect(rect);
246 static void
247 determine_bounds_draw_round_rect(void* _state, const BRect& _rect,
248 const BPoint&, bool fill)
250 determine_bounds_draw_rect(_state, _rect, fill);
254 static void
255 determine_bounds_bezier(BoundingBoxState* state, const BPoint* viewPoints,
256 BRect& outRect)
258 // Note: this is an approximation which results in a rectangle which
259 // encloses all four control points. That will always enclose the curve,
260 // although not necessarily tightly, but it's good enough for the purpose.
261 // The exact bounding box of a bezier curve is not trivial to determine,
262 // (need to calculate derivative of the curve) and we're going for
263 // performance here.
264 BPoint points[4];
265 state->PenToLocalTransform().Apply(points, viewPoints, 4);
266 BPoint topLeft = points[0];
267 BPoint bottomRight = points[0];
268 for (uint32 index = 1; index < 4; index++) {
269 if (points[index].x < topLeft.x || points[index].y < topLeft.y)
270 topLeft = points[index];
271 if (points[index].x > topLeft.x || points[index].y > topLeft.y)
272 bottomRight = points[index];
274 outRect.SetLeftTop(topLeft);
275 outRect.SetRightBottom(bottomRight);
279 static void
280 determine_bounds_draw_bezier(void* _state, size_t numPoints,
281 const BPoint viewPoints[], bool fill)
283 TRACE_BB("%p draw bezier fill=%d (%.2f %.2f) (%.2f %.2f) "
284 "(%.2f %.2f) (%.2f %.2f)\n",
285 _state,
286 fill,
287 viewPoints[0].x, viewPoints[0].y,
288 viewPoints[1].x, viewPoints[1].y,
289 viewPoints[2].x, viewPoints[2].y,
290 viewPoints[3].x, viewPoints[3].y);
291 BoundingBoxState* const state =
292 reinterpret_cast<BoundingBoxState*>(_state);
294 const size_t kSupportedPoints = 4;
295 if (numPoints != kSupportedPoints)
296 return;
298 BRect rect;
299 determine_bounds_bezier(state, viewPoints, rect);
300 if (!fill)
301 expand_rect_for_pen_size(state, rect);
302 state->IncludeRect(rect);
306 static void
307 determine_bounds_draw_ellipse(void* _state, const BRect& _rect, bool fill)
309 TRACE_BB("%p draw ellipse fill=%d (%.2f %.2f) (%.2f %.2f)\n", _state, fill,
310 _rect.left, _rect.top, _rect.right, _rect.bottom);
311 BoundingBoxState* const state =
312 reinterpret_cast<BoundingBoxState*>(_state);
314 BRect rect = _rect;
315 state->PenToLocalTransform().Apply(&rect);
316 if (!fill)
317 expand_rect_for_pen_size(state, rect);
318 state->IncludeRect(rect);
322 static void
323 determine_bounds_draw_arc(void* _state, const BPoint& center,
324 const BPoint& radii, float, float, bool fill)
326 BRect rect(center.x - radii.x, center.y - radii.y,
327 center.x + radii.x - 1, center.y + radii.y - 1);
328 determine_bounds_draw_ellipse(_state, rect, fill);
332 static void
333 determine_bounds_polygon(BoundingBoxState* state, int32 numPoints,
334 const BPoint* viewPoints, BRect& outRect)
336 if (numPoints <= 0)
337 return;
339 if (numPoints <= 200) {
340 // fast path: no malloc/free, also avoid
341 // constructor/destructor calls
342 char data[200 * sizeof(BPoint)];
343 BPoint* points = (BPoint*)data;
345 state->PenToLocalTransform().Apply(points, viewPoints, numPoints);
346 get_polygon_frame(points, numPoints, &outRect);
348 } else {
349 // avoid constructor/destructor calls by
350 // using malloc instead of new []
351 BPoint* points = (BPoint*)malloc(numPoints * sizeof(BPoint));
352 if (points == NULL)
353 return;
355 state->PenToLocalTransform().Apply(points, viewPoints, numPoints);
356 get_polygon_frame(points, numPoints, &outRect);
358 free(points);
363 void
364 determine_bounds_draw_polygon(void* _state, size_t numPoints,
365 const BPoint viewPoints[], bool, bool fill)
367 TRACE_BB("%p draw polygon fill=%d (%ld points)\n", _state, fill, numPoints);
368 BoundingBoxState* const state =
369 reinterpret_cast<BoundingBoxState*>(_state);
371 BRect rect;
372 determine_bounds_polygon(state, numPoints, viewPoints, rect);
373 if (!fill)
374 expand_rect_for_pen_size(state, rect);
375 state->IncludeRect(rect);
379 static void
380 determine_bounds_draw_shape(void* _state, const BShape& shape, bool fill)
382 BRect rect = shape.Bounds();
384 TRACE_BB("%p stroke shape (bounds %.2f %.2f %.2f %.2f)\n", _state,
385 rect.left, rect.top, rect.right, rect.bottom);
386 BoundingBoxState* const state =
387 reinterpret_cast<BoundingBoxState*>(_state);
389 state->PenToLocalTransform().Apply(&rect);
390 if (!fill)
391 expand_rect_for_pen_size(state, rect);
392 state->IncludeRect(rect);
396 static void
397 determine_bounds_draw_string(void* _state, const char* string, size_t _length,
398 float deltaSpace, float deltaNonSpace)
400 TRACE_BB("%p string '%s'\n", _state, string);
401 BoundingBoxState* const state =
402 reinterpret_cast<BoundingBoxState*>(_state);
404 ServerFont font = state->GetDrawState()->Font();
406 escapement_delta delta = { deltaSpace, deltaNonSpace };
407 BRect rect;
408 int32 length = _length;
409 font.GetBoundingBoxesForStrings((char**)&string, &length, 1, &rect,
410 B_SCREEN_METRIC, &delta);
412 BPoint location = state->GetDrawState()->PenLocation();
414 state->PenToLocalTransform().Apply(&location);
415 rect.OffsetBy(location);
416 state->IncludeRect(rect);
418 state->PenToLocalTransform().Apply(&location);
419 state->GetDrawState()->SetPenLocation(location);
423 static void
424 determine_bounds_draw_pixels(void* _state, const BRect&, const BRect& _dest,
425 uint32, uint32, size_t, color_space, uint32, const void*, size_t)
427 TRACE_BB("%p pixels (dest %.2f %.2f %.2f %.2f)\n", _state,
428 _dest.left, _dest.top, _dest.right, _dest.bottom);
429 BoundingBoxState* const state =
430 reinterpret_cast<BoundingBoxState*>(_state);
432 BRect dest = _dest;
433 state->PenToLocalTransform().Apply(&dest);
434 state->IncludeRect(dest);
438 static void
439 draw_picture(void* _state, const BPoint& where, int32 token)
441 TRACE_BB("%p picture (unimplemented)\n", _state);
443 // TODO
444 (void)_state;
445 (void)where;
446 (void)token;
450 static void
451 set_clipping_rects(void* _state, size_t numRects, const BRect rects[])
453 TRACE_BB("%p cliping rects (%ld rects)\n", _state, numRects);
455 // TODO
456 (void)_state;
457 (void)rects;
458 (void)numRects;
462 static void
463 clip_to_picture(void* _state, int32 pictureToken, const BPoint& where,
464 bool clipToInverse)
466 TRACE_BB("%p clip to picture (unimplemented)\n", _state);
468 // TODO
472 static void
473 push_state(void* _state)
475 TRACE_BB("%p push state\n", _state);
476 BoundingBoxState* const state =
477 reinterpret_cast<BoundingBoxState*>(_state);
479 state->PushDrawState();
483 static void
484 pop_state(void* _state)
486 TRACE_BB("%p pop state\n", _state);
487 BoundingBoxState* const state =
488 reinterpret_cast<BoundingBoxState*>(_state);
490 state->PopDrawState();
494 static void
495 enter_state_change(void*)
500 static void
501 exit_state_change(void*)
506 static void
507 enter_font_state(void*)
512 static void
513 exit_font_state(void*)
518 static void
519 set_origin(void* _state, const BPoint& pt)
521 TRACE_BB("%p set origin %.2f %.2f\n", _state, pt.x, pt.y);
522 BoundingBoxState* const state =
523 reinterpret_cast<BoundingBoxState*>(_state);
524 state->GetDrawState()->SetOrigin(pt);
528 static void
529 set_pen_location(void* _state, const BPoint& pt)
531 TRACE_BB("%p set pen location %.2f %.2f\n", _state, pt.x, pt.y);
532 BoundingBoxState* const state =
533 reinterpret_cast<BoundingBoxState*>(_state);
534 state->GetDrawState()->SetPenLocation(pt);
538 static void
539 set_drawing_mode(void*, drawing_mode)
544 static void
545 set_line_mode(void* _state, cap_mode capMode, join_mode joinMode,
546 float miterLimit)
548 BoundingBoxState* const state =
549 reinterpret_cast<BoundingBoxState*>(_state);
551 DrawState* drawState = state->GetDrawState();
552 drawState->SetLineCapMode(capMode);
553 drawState->SetLineJoinMode(joinMode);
554 drawState->SetMiterLimit(miterLimit);
558 static void
559 set_pen_size(void* _state, float size)
561 TRACE_BB("%p set pen size %.2f\n", _state, size);
562 BoundingBoxState* const state =
563 reinterpret_cast<BoundingBoxState*>(_state);
565 state->GetDrawState()->SetPenSize(size);
569 static void
570 set_fore_color(void* _state, const rgb_color& color)
572 BoundingBoxState* const state =
573 reinterpret_cast<BoundingBoxState*>(_state);
575 state->GetDrawState()->SetHighColor(color);
579 static void
580 set_back_color(void* _state, const rgb_color& color)
582 BoundingBoxState* const state =
583 reinterpret_cast<BoundingBoxState*>(_state);
585 state->GetDrawState()->SetLowColor(color);
589 static void
590 set_stipple_pattern(void* _state, const pattern& _pattern)
592 BoundingBoxState* const state =
593 reinterpret_cast<BoundingBoxState*>(_state);
595 state->GetDrawState()->SetPattern(Pattern(_pattern));
599 static void
600 set_scale(void* _state, float scale)
602 BoundingBoxState* const state =
603 reinterpret_cast<BoundingBoxState*>(_state);
605 state->GetDrawState()->SetScale(scale);
609 static void
610 set_font_family(void* _state, const char* _family, size_t length)
612 BoundingBoxState* const state =
613 reinterpret_cast<BoundingBoxState*>(_state);
615 BString family(_family, length);
616 FontStyle* fontStyle = gFontManager->GetStyleByIndex(family, 0);
617 ServerFont font;
618 font.SetStyle(fontStyle);
619 state->GetDrawState()->SetFont(font, B_FONT_FAMILY_AND_STYLE);
623 static void
624 set_font_style(void* _state, const char* _style, size_t length)
626 BoundingBoxState* const state =
627 reinterpret_cast<BoundingBoxState*>(_state);
629 BString style(_style, length);
630 ServerFont font(state->GetDrawState()->Font());
631 FontStyle* fontStyle = gFontManager->GetStyle(font.Family(), style);
632 font.SetStyle(fontStyle);
633 state->GetDrawState()->SetFont(font, B_FONT_FAMILY_AND_STYLE);
637 static void
638 set_font_spacing(void* _state, uint8 spacing)
640 BoundingBoxState* const state =
641 reinterpret_cast<BoundingBoxState*>(_state);
643 ServerFont font;
644 font.SetSpacing(spacing);
645 state->GetDrawState()->SetFont(font, B_FONT_SPACING);
649 static void
650 set_font_size(void* _state, float size)
652 BoundingBoxState* const state =
653 reinterpret_cast<BoundingBoxState*>(_state);
655 ServerFont font;
656 font.SetSize(size);
657 state->GetDrawState()->SetFont(font, B_FONT_SIZE);
661 static void
662 set_font_rotate(void* _state, float rotation)
664 BoundingBoxState* const state =
665 reinterpret_cast<BoundingBoxState*>(_state);
667 ServerFont font;
668 font.SetRotation(rotation);
669 state->GetDrawState()->SetFont(font, B_FONT_ROTATION);
673 static void
674 set_font_encoding(void* _state, uint8 encoding)
676 BoundingBoxState* const state =
677 reinterpret_cast<BoundingBoxState*>(_state);
679 ServerFont font;
680 font.SetEncoding(encoding);
681 state->GetDrawState()->SetFont(font, B_FONT_ENCODING);
685 static void
686 set_font_flags(void* _state, uint32 flags)
688 BoundingBoxState* const state =
689 reinterpret_cast<BoundingBoxState*>(_state);
691 ServerFont font;
692 font.SetFlags(flags);
693 state->GetDrawState()->SetFont(font, B_FONT_FLAGS);
697 static void
698 set_font_shear(void* _state, float shear)
700 BoundingBoxState* const state =
701 reinterpret_cast<BoundingBoxState*>(_state);
703 ServerFont font;
704 font.SetShear(shear);
705 state->GetDrawState()->SetFont(font, B_FONT_SHEAR);
709 static void
710 set_font_face(void* _state, uint16 face)
712 BoundingBoxState* const state =
713 reinterpret_cast<BoundingBoxState*>(_state);
715 ServerFont font;
716 font.SetFace(face);
717 state->GetDrawState()->SetFont(font, B_FONT_FACE);
721 static void
722 set_blending_mode(void*, source_alpha, alpha_function)
727 static void
728 set_transform(void* _state, const BAffineTransform& transform)
730 TRACE_BB("%p transform\n", _state);
731 BoundingBoxState* const state =
732 reinterpret_cast<BoundingBoxState*>(_state);
733 state->GetDrawState()->SetTransform(transform);
737 static void
738 translate_by(void* _state, double x, double y)
740 TRACE_BB("%p translate\n", _state);
741 BoundingBoxState* const state =
742 reinterpret_cast<BoundingBoxState*>(_state);
743 BAffineTransform transform = state->GetDrawState()->Transform();
744 transform.PreTranslateBy(x, y);
745 state->GetDrawState()->SetTransform(transform);
749 static void
750 scale_by(void* _state, double x, double y)
752 TRACE_BB("%p scale\n", _state);
753 BoundingBoxState* const state =
754 reinterpret_cast<BoundingBoxState*>(_state);
755 BAffineTransform transform = state->GetDrawState()->Transform();
756 transform.PreScaleBy(x, y);
757 state->GetDrawState()->SetTransform(transform);
761 static void
762 rotate_by(void* _state, double angleRadians)
764 TRACE_BB("%p rotate\n", _state);
765 BoundingBoxState* const state =
766 reinterpret_cast<BoundingBoxState*>(_state);
767 BAffineTransform transform = state->GetDrawState()->Transform();
768 transform.PreRotateBy(angleRadians);
769 state->GetDrawState()->SetTransform(transform);
773 static void
774 determine_bounds_nested_layer(void* _state, Layer* layer)
776 TRACE_BB("%p nested layer\n", _state);
777 BoundingBoxState* const state =
778 reinterpret_cast<BoundingBoxState*>(_state);
780 BRect boundingBox;
781 PictureBoundingBoxPlayer::Play(layer, state->GetDrawState(), &boundingBox);
782 if (boundingBox.IsValid())
783 state->IncludeRect(boundingBox);
787 static const BPrivate::picture_player_callbacks
788 kPictureBoundingBoxPlayerCallbacks = {
789 move_pen_by,
790 determine_bounds_stroke_line,
791 determine_bounds_draw_rect,
792 determine_bounds_draw_round_rect,
793 determine_bounds_draw_bezier,
794 determine_bounds_draw_arc,
795 determine_bounds_draw_ellipse,
796 determine_bounds_draw_polygon,
797 determine_bounds_draw_shape,
798 determine_bounds_draw_string,
799 determine_bounds_draw_pixels,
800 draw_picture,
801 set_clipping_rects,
802 clip_to_picture,
803 push_state,
804 pop_state,
805 enter_state_change,
806 exit_state_change,
807 enter_font_state,
808 exit_font_state,
809 set_origin,
810 set_pen_location,
811 set_drawing_mode,
812 set_line_mode,
813 set_pen_size,
814 set_fore_color,
815 set_back_color,
816 set_stipple_pattern,
817 set_scale,
818 set_font_family,
819 set_font_style,
820 set_font_spacing,
821 set_font_size,
822 set_font_rotate,
823 set_font_encoding,
824 set_font_flags,
825 set_font_shear,
826 set_font_face,
827 set_blending_mode,
828 set_transform,
829 translate_by,
830 scale_by,
831 rotate_by,
832 determine_bounds_nested_layer
836 // #pragma mark - PictureBoundingBoxPlayer
839 /* static */ void
840 PictureBoundingBoxPlayer::Play(ServerPicture* picture,
841 const DrawState* drawState, BRect* outBoundingBox)
843 State state(drawState, outBoundingBox);
845 BMallocIO* mallocIO = dynamic_cast<BMallocIO*>(picture->fData);
846 if (mallocIO == NULL)
847 return;
849 BPrivate::PicturePlayer player(mallocIO->Buffer(),
850 mallocIO->BufferLength(), ServerPicture::PictureList::Private(
851 picture->fPictures).AsBList());
852 player.Play(kPictureBoundingBoxPlayerCallbacks,
853 sizeof(kPictureBoundingBoxPlayerCallbacks), &state);