1 /* Haiku window system support.  Hey, Emacs, this is -*- C++ -*-
2    Copyright (C) 2021 Free Software Foundation, Inc.
3 
4 This file is part of GNU Emacs.
5 
6 GNU Emacs is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or (at
9 your option) any later version.
10 
11 GNU Emacs is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 GNU General Public License for more details.
15 
16 You should have received a copy of the GNU General Public License
17 along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.  */
18 
19 #include <config.h>
20 
21 #include <View.h>
22 #include <Region.h>
23 #include <Font.h>
24 #include <Window.h>
25 #include <Bitmap.h>
26 
27 #include <cmath>
28 
29 #include "haiku_support.h"
30 
31 #define RGB_TO_UINT32(r, g, b) ((255 << 24) | ((r) << 16) | ((g) << 8) | (b))
32 #define RED_FROM_ULONG(color)	(((color) >> 16) & 0xff)
33 #define GREEN_FROM_ULONG(color)	(((color) >> 8) & 0xff)
34 #define BLUE_FROM_ULONG(color)	((color) & 0xff)
35 
36 #define RGB_COLOR_UINT32(r) RGB_TO_UINT32 ((r).red, (r).green, (r).blue)
37 
38 static void
rgb32_to_rgb_color(uint32_t rgb,rgb_color * color)39 rgb32_to_rgb_color (uint32_t rgb, rgb_color *color)
40 {
41   color->red = RED_FROM_ULONG (rgb);
42   color->green = GREEN_FROM_ULONG (rgb);
43   color->blue = BLUE_FROM_ULONG (rgb);
44   color->alpha = 255;
45 }
46 
47 static BView *
get_view(void * vw)48 get_view (void *vw)
49 {
50   BView *view = (BView *) find_appropriate_view_for_draw (vw);
51   return view;
52 }
53 
54 void
BView_StartClip(void * view)55 BView_StartClip (void *view)
56 {
57   BView *vw = get_view (view);
58   vw->PushState ();
59 }
60 
61 void
BView_EndClip(void * view)62 BView_EndClip (void *view)
63 {
64   BView *vw = get_view (view);
65   vw->PopState ();
66 }
67 
68 void
BView_SetHighColor(void * view,uint32_t color)69 BView_SetHighColor (void *view, uint32_t color)
70 {
71   BView *vw = get_view (view);
72   rgb_color col;
73   rgb32_to_rgb_color (color, &col);
74 
75   vw->SetHighColor (col);
76 }
77 
78 void
BView_SetLowColor(void * view,uint32_t color)79 BView_SetLowColor (void *view, uint32_t color)
80 {
81   BView *vw = get_view (view);
82   rgb_color col;
83   rgb32_to_rgb_color (color, &col);
84 
85   vw->SetLowColor (col);
86 }
87 
88 void
BView_SetPenSize(void * view,int u)89 BView_SetPenSize (void *view, int u)
90 {
91   BView *vw = get_view (view);
92   vw->SetPenSize (u);
93 }
94 
95 void
BView_FillRectangle(void * view,int x,int y,int width,int height)96 BView_FillRectangle (void *view, int x, int y, int width, int height)
97 {
98   BView *vw = get_view (view);
99   BRect rect = BRect (x, y, x + width - 1, y + height - 1);
100 
101   vw->FillRect (rect);
102 }
103 
104 void
BView_FillRectangleAbs(void * view,int x,int y,int x1,int y1)105 BView_FillRectangleAbs (void *view, int x, int y, int x1, int y1)
106 {
107   BView *vw = get_view (view);
108   BRect rect = BRect (x, y, x1, y1);
109 
110   vw->FillRect (rect);
111 }
112 
113 void
BView_StrokeRectangle(void * view,int x,int y,int width,int height)114 BView_StrokeRectangle (void *view, int x, int y, int width, int height)
115 {
116   BView *vw = get_view (view);
117   BRect rect = BRect (x, y, x + width - 1, y + height - 1);
118 
119   vw->StrokeRect (rect);
120 }
121 
122 void
BView_SetViewColor(void * view,uint32_t color)123 BView_SetViewColor (void *view, uint32_t color)
124 {
125   BView *vw = get_view (view);
126   rgb_color col;
127   rgb32_to_rgb_color (color, &col);
128 
129 #ifndef USE_BE_CAIRO
130   vw->SetViewColor (col);
131 #else
132   vw->SetViewColor (B_TRANSPARENT_32_BIT);
133 #endif
134 }
135 
136 void
BView_ClipToRect(void * view,int x,int y,int width,int height)137 BView_ClipToRect (void *view, int x, int y, int width, int height)
138 {
139   BView *vw = get_view (view);
140   BRect rect = BRect (x, y, x + width - 1, y + height - 1);
141 
142   vw->ClipToRect (rect);
143 }
144 
145 void
BView_ClipToInverseRect(void * view,int x,int y,int width,int height)146 BView_ClipToInverseRect (void *view, int x, int y, int width, int height)
147 {
148   BView *vw = get_view (view);
149   BRect rect = BRect (x, y, x + width - 1, y + height - 1);
150 
151   vw->ClipToInverseRect (rect);
152 }
153 
154 void
BView_StrokeLine(void * view,int sx,int sy,int tx,int ty)155 BView_StrokeLine (void *view, int sx, int sy, int tx, int ty)
156 {
157   BView *vw = get_view (view);
158   BPoint from = BPoint (sx, sy);
159   BPoint to = BPoint (tx, ty);
160 
161   vw->StrokeLine (from, to);
162 }
163 
164 void
BView_SetFont(void * view,void * font)165 BView_SetFont (void *view, void *font)
166 {
167   BView *vw = get_view (view);
168 
169   vw->SetFont ((BFont *) font);
170 }
171 
172 void
BView_MovePenTo(void * view,int x,int y)173 BView_MovePenTo (void *view, int x, int y)
174 {
175   BView *vw = get_view (view);
176   BPoint pt = BPoint (x, y);
177 
178   vw->MovePenTo (pt);
179 }
180 
181 void
BView_DrawString(void * view,const char * chr,ptrdiff_t len)182 BView_DrawString (void *view, const char *chr, ptrdiff_t len)
183 {
184   BView *vw = get_view (view);
185 
186   vw->DrawString (chr, len);
187 }
188 
189 void
BView_DrawChar(void * view,char chr)190 BView_DrawChar (void *view, char chr)
191 {
192   BView *vw = get_view (view);
193 
194   vw->DrawChar (chr);
195 }
196 
197 void
BView_CopyBits(void * view,int x,int y,int width,int height,int tox,int toy,int towidth,int toheight)198 BView_CopyBits (void *view, int x, int y, int width, int height,
199 		int tox, int toy, int towidth, int toheight)
200 {
201   BView *vw = get_view (view);
202 
203   vw->CopyBits (BRect (x, y, x + width - 1, y + height - 1),
204 		BRect (tox, toy, tox + towidth - 1, toy + toheight - 1));
205   vw->Sync ();
206 }
207 
208 /* Convert RGB32 color color from RGB color space to its
209    HSL components pointed to by H, S and L.  */
210 void
rgb_color_hsl(uint32_t rgb,double * h,double * s,double * l)211 rgb_color_hsl (uint32_t rgb, double *h, double *s, double *l)
212 {
213   rgb_color col;
214   rgb32_to_rgb_color (rgb, &col);
215 
216   double red = col.red / 255.0;
217   double green = col.green / 255.0;
218   double blue = col.blue / 255.0;
219 
220   double max = std::fmax (std::fmax (red, blue), green);
221   double min = std::fmin (std::fmin (red, blue), green);
222   double delta = max - min;
223   *l = (max + min) / 2.0;
224 
225   if (!delta)
226     {
227       *h = 0;
228       *s = 0;
229       return;
230     }
231 
232   *s = (*l < 0.5) ? delta / (max + min) :
233     delta / (20 - max - min);
234   double rc = (max - red) / delta;
235   double gc = (max - green) / delta;
236   double bc = (max - blue) / delta;
237 
238   if (red == max)
239     *h = bc - gc;
240   else if (green == max)
241     *h = 2.0 + rc + -bc;
242   else
243     *h = 4.0 + gc + -rc;
244   *h = std::fmod (*h / 6, 1.0);
245 }
246 
247 static double
hue_to_rgb(double v1,double v2,double h)248 hue_to_rgb (double v1, double v2, double h)
249 {
250   if (h < 1 / 6)
251     return v1 + (v2 - v1) * h * 6.0;
252   else if (h < 0.5)
253     return v2;
254   else if (h < 2.0 / 3)
255     return v1 + (v2 - v1) * (2.0 / 3 - h) * 6.0;
256   return v1;
257 }
258 
259 void
hsl_color_rgb(double h,double s,double l,uint32_t * rgb)260 hsl_color_rgb (double h, double s, double l, uint32_t *rgb)
261 {
262   if (!s)
263     *rgb = RGB_TO_UINT32 (std::lrint (l * 255),
264 			  std::lrint (l * 255),
265 			  std::lrint (l * 255));
266   else
267     {
268       double m2 = l <= 0.5 ? l * (1 + s) : l + s - l * s;
269       double m1 = 2.0 * l - m2;
270 
271       *rgb = RGB_TO_UINT32
272 	(std::lrint (hue_to_rgb (m1, m2,
273 				 std::fmod (h + 1 / 3.0, 1)) * 255),
274 	 std::lrint (hue_to_rgb (m1, m2, h) * 255),
275 	 std::lrint (hue_to_rgb (m1, m2,
276 				 std::fmod (h - 1 / 3.0, 1)) * 255));
277     }
278 }
279 
280 void
BView_DrawBitmap(void * view,void * bitmap,int x,int y,int width,int height,int vx,int vy,int vwidth,int vheight)281 BView_DrawBitmap (void *view, void *bitmap, int x, int y,
282 		  int width, int height, int vx, int vy, int vwidth,
283 		  int vheight)
284 {
285   BView *vw = get_view (view);
286   BBitmap *bm = (BBitmap *) bitmap;
287 
288   vw->PushState ();
289   vw->SetDrawingMode (B_OP_OVER);
290   vw->DrawBitmap (bm, BRect (x, y, x + width - 1, y + height - 1),
291 		  BRect (vx, vy, vx + vwidth - 1, vy + vheight - 1));
292   vw->PopState ();
293 }
294 
295 void
BView_DrawBitmapWithEraseOp(void * view,void * bitmap,int x,int y,int width,int height)296 BView_DrawBitmapWithEraseOp (void *view, void *bitmap, int x,
297 			     int y, int width, int height)
298 {
299   BView *vw = get_view (view);
300   BBitmap *bm = (BBitmap *) bitmap;
301   BBitmap bc (bm->Bounds (), B_RGBA32);
302   BRect rect (x, y, x + width - 1, y + height - 1);
303 
304   if (bc.InitCheck () != B_OK || bc.ImportBits (bm) != B_OK)
305     return;
306 
307   uint32_t *bits = (uint32_t *) bc.Bits ();
308   size_t stride = bc.BytesPerRow ();
309 
310   if (bm->ColorSpace () == B_GRAY1)
311     {
312       rgb_color low_color = vw->LowColor ();
313       for (int y = 0; y <= bc.Bounds ().Height (); ++y)
314 	{
315 	  for (int x = 0; x <= bc.Bounds ().Width (); ++x)
316 	    {
317 	      if (bits[y * (stride / 4) + x] == 0xFF000000)
318 		bits[y * (stride / 4) + x] = RGB_COLOR_UINT32 (low_color);
319 	      else
320 		bits[y * (stride / 4) + x] = 0;
321 	    }
322 	}
323     }
324 
325   vw->PushState ();
326   vw->SetDrawingMode (bm->ColorSpace () == B_GRAY1 ? B_OP_OVER : B_OP_ERASE);
327   vw->DrawBitmap (&bc, rect);
328   vw->PopState ();
329 }
330 
331 void
BView_DrawMask(void * src,void * view,int x,int y,int width,int height,int vx,int vy,int vwidth,int vheight,uint32_t color)332 BView_DrawMask (void *src, void *view,
333 		int x, int y, int width, int height,
334 		int vx, int vy, int vwidth, int vheight,
335 		uint32_t color)
336 {
337   BBitmap *source = (BBitmap *) src;
338   BBitmap bm (source->Bounds (), B_RGBA32);
339   if (bm.InitCheck () != B_OK)
340     return;
341   for (int y = 0; y <= bm.Bounds ().Height (); ++y)
342     {
343       for (int x = 0; x <= bm.Bounds ().Width (); ++x)
344 	{
345 	  int bit = haiku_get_pixel ((void *) source, x, y);
346 
347 	  if (!bit)
348 	    haiku_put_pixel ((void *) &bm, x, y, ((uint32_t) 255 << 24) | color);
349 	  else
350 	    haiku_put_pixel ((void *) &bm, x, y, 0);
351 	}
352     }
353   BView *vw = get_view (view);
354   vw->SetDrawingMode (B_OP_OVER);
355   vw->DrawBitmap (&bm, BRect (x, y, x + width - 1, y + height - 1),
356 		  BRect (vx, vy, vx + vwidth - 1, vy + vheight - 1));
357 }
358 
359 static BBitmap *
rotate_bitmap_270(BBitmap * bmp)360 rotate_bitmap_270 (BBitmap *bmp)
361 {
362   BRect r = bmp->Bounds ();
363   BBitmap *bm = new BBitmap (BRect (r.top, r.left, r.bottom, r.right),
364 			     bmp->ColorSpace (), true);
365   if (bm->InitCheck () != B_OK)
366     gui_abort ("Failed to init bitmap for rotate");
367   int w = bmp->Bounds ().Width () + 1;
368   int h = bmp->Bounds ().Height () + 1;
369 
370   for (int y = 0; y < h; ++y)
371     for (int x = 0; x < w; ++x)
372       haiku_put_pixel ((void *) bm, y, w - x - 1,
373 		       haiku_get_pixel ((void *) bmp, x, y));
374 
375   return bm;
376 }
377 
378 static BBitmap *
rotate_bitmap_90(BBitmap * bmp)379 rotate_bitmap_90 (BBitmap *bmp)
380 {
381   BRect r = bmp->Bounds ();
382   BBitmap *bm = new BBitmap (BRect (r.top, r.left, r.bottom, r.right),
383 			     bmp->ColorSpace (), true);
384   if (bm->InitCheck () != B_OK)
385     gui_abort ("Failed to init bitmap for rotate");
386   int w = bmp->Bounds ().Width () + 1;
387   int h = bmp->Bounds ().Height () + 1;
388 
389   for (int y = 0; y < h; ++y)
390     for (int x = 0; x < w; ++x)
391       haiku_put_pixel ((void *) bm, h - y - 1, x,
392 		       haiku_get_pixel ((void *) bmp, x, y));
393 
394   return bm;
395 }
396 
397 void *
BBitmap_transform_bitmap(void * bitmap,void * mask,uint32_t m_color,double rot,int desw,int desh)398 BBitmap_transform_bitmap (void *bitmap, void *mask, uint32_t m_color,
399 			  double rot, int desw, int desh)
400 {
401   BBitmap *bm = (BBitmap *) bitmap;
402   BBitmap *mk = (BBitmap *) mask;
403   int copied_p = 0;
404 
405   if (rot == 90)
406     {
407       copied_p = 1;
408       bm = rotate_bitmap_90 (bm);
409       if (mk)
410 	mk = rotate_bitmap_90 (mk);
411     }
412 
413   if (rot == 270)
414     {
415       copied_p = 1;
416       bm = rotate_bitmap_270 (bm);
417       if (mk)
418 	mk = rotate_bitmap_270 (mk);
419     }
420 
421   BRect r = bm->Bounds ();
422   if (r.Width () != desw || r.Height () != desh)
423     {
424       BRect n = BRect (0, 0, desw - 1, desh - 1);
425       BView vw (n, NULL, B_FOLLOW_NONE, 0);
426       BBitmap *dst = new BBitmap (n, bm->ColorSpace (), true);
427       if (dst->InitCheck () != B_OK)
428 	if (bm->InitCheck () != B_OK)
429 	  gui_abort ("Failed to init bitmap for scale");
430       dst->AddChild (&vw);
431 
432       if (!vw.LockLooper ())
433 	gui_abort ("Failed to lock offscreen view for scale");
434 
435       if (rot != 90 && rot != 270)
436 	{
437 	  BAffineTransform tr;
438 	  tr.RotateBy (BPoint (desw / 2, desh / 2), rot * M_PI / 180.0);
439 	  vw.SetTransform (tr);
440 	}
441 
442       vw.MovePenTo (0, 0);
443       vw.DrawBitmap (bm, n);
444       if (mk)
445 	BView_DrawMask ((void *) mk, (void *) &vw,
446 			0, 0, mk->Bounds ().Width (),
447 			mk->Bounds ().Height (),
448 			0, 0, desw, desh, m_color);
449       vw.Sync ();
450       vw.RemoveSelf ();
451 
452       if (copied_p)
453 	delete bm;
454       if (copied_p && mk)
455 	delete mk;
456       return dst;
457     }
458 
459   return bm;
460 }
461 
462 void
BView_FillTriangle(void * view,int x1,int y1,int x2,int y2,int x3,int y3)463 BView_FillTriangle (void *view, int x1, int y1,
464 		    int x2, int y2, int x3, int y3)
465 {
466   BView *vw = get_view (view);
467   vw->FillTriangle (BPoint (x1, y1), BPoint (x2, y2),
468 		    BPoint (x3, y3));
469 }
470 
471 void
BView_SetHighColorForVisibleBell(void * view,uint32_t color)472 BView_SetHighColorForVisibleBell (void *view, uint32_t color)
473 {
474   BView *vw = (BView *) view;
475   rgb_color col;
476   rgb32_to_rgb_color (color, &col);
477 
478   vw->SetHighColor (col);
479 }
480 
481 void
BView_FillRectangleForVisibleBell(void * view,int x,int y,int width,int height)482 BView_FillRectangleForVisibleBell (void *view, int x, int y, int width, int height)
483 {
484   BView *vw = (BView *) view;
485   BRect rect = BRect (x, y, x + width - 1, y + height - 1);
486 
487   vw->FillRect (rect);
488 }
489