Painter.cpp 48 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305
  1. /*
  2. * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
  3. * All rights reserved.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions are met:
  7. *
  8. * 1. Redistributions of source code must retain the above copyright notice, this
  9. * list of conditions and the following disclaimer.
  10. *
  11. * 2. Redistributions in binary form must reproduce the above copyright notice,
  12. * this list of conditions and the following disclaimer in the documentation
  13. * and/or other materials provided with the distribution.
  14. *
  15. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  16. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  17. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  18. * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
  19. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  20. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  21. * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  22. * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  23. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  24. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  25. */
  26. #include "Painter.h"
  27. #include "Bitmap.h"
  28. #include "Emoji.h"
  29. #include "Font.h"
  30. #include <AK/Assertions.h>
  31. #include <AK/Function.h>
  32. #include <AK/Memory.h>
  33. #include <AK/QuickSort.h>
  34. #include <AK/StdLibExtras.h>
  35. #include <AK/StringBuilder.h>
  36. #include <AK/Utf8View.h>
  37. #include <LibGfx/CharacterBitmap.h>
  38. #include <LibGfx/Path.h>
  39. #include <math.h>
  40. #include <stdio.h>
  41. #include <unistd.h>
  42. #if defined(__GNUC__) && !defined(__clang__)
  43. # pragma GCC optimize("O3")
  44. #endif
  45. namespace Gfx {
  46. template<BitmapFormat format = BitmapFormat::Invalid>
  47. ALWAYS_INLINE Color get_pixel(const Gfx::Bitmap& bitmap, int x, int y)
  48. {
  49. if constexpr (format == BitmapFormat::Indexed8)
  50. return bitmap.palette_color(bitmap.bits(y)[x]);
  51. if constexpr (format == BitmapFormat::RGB32)
  52. return Color::from_rgb(bitmap.scanline(y)[x]);
  53. if constexpr (format == BitmapFormat::RGBA32)
  54. return Color::from_rgba(bitmap.scanline(y)[x]);
  55. return bitmap.get_pixel(x, y);
  56. }
  57. Painter::Painter(Gfx::Bitmap& bitmap)
  58. : m_target(bitmap)
  59. {
  60. m_state_stack.append(State());
  61. state().font = &Font::default_font();
  62. state().clip_rect = { { 0, 0 }, bitmap.size() };
  63. m_clip_origin = state().clip_rect;
  64. }
  65. Painter::~Painter()
  66. {
  67. }
  68. void Painter::fill_rect_with_draw_op(const Rect& a_rect, Color color)
  69. {
  70. auto rect = a_rect.translated(translation()).intersected(clip_rect());
  71. if (rect.is_empty())
  72. return;
  73. RGBA32* dst = m_target->scanline(rect.top()) + rect.left();
  74. const size_t dst_skip = m_target->pitch() / sizeof(RGBA32);
  75. for (int i = rect.height() - 1; i >= 0; --i) {
  76. for (int j = 0; j < rect.width(); ++j)
  77. set_pixel_with_draw_op(dst[j], color);
  78. dst += dst_skip;
  79. }
  80. }
  81. void Painter::clear_rect(const Rect& a_rect, Color color)
  82. {
  83. auto rect = a_rect.translated(translation()).intersected(clip_rect());
  84. if (rect.is_empty())
  85. return;
  86. ASSERT(m_target->rect().contains(rect));
  87. RGBA32* dst = m_target->scanline(rect.top()) + rect.left();
  88. const size_t dst_skip = m_target->pitch() / sizeof(RGBA32);
  89. for (int i = rect.height() - 1; i >= 0; --i) {
  90. fast_u32_fill(dst, color.value(), rect.width());
  91. dst += dst_skip;
  92. }
  93. }
  94. void Painter::fill_rect(const Rect& a_rect, Color color)
  95. {
  96. if (color.alpha() == 0)
  97. return;
  98. if (draw_op() != DrawOp::Copy) {
  99. fill_rect_with_draw_op(a_rect, color);
  100. return;
  101. }
  102. if (color.alpha() == 0xff) {
  103. clear_rect(a_rect, color);
  104. return;
  105. }
  106. auto rect = a_rect.translated(translation()).intersected(clip_rect());
  107. if (rect.is_empty())
  108. return;
  109. ASSERT(m_target->rect().contains(rect));
  110. RGBA32* dst = m_target->scanline(rect.top()) + rect.left();
  111. const size_t dst_skip = m_target->pitch() / sizeof(RGBA32);
  112. for (int i = rect.height() - 1; i >= 0; --i) {
  113. for (int j = 0; j < rect.width(); ++j)
  114. dst[j] = Color::from_rgba(dst[j]).blend(color).value();
  115. dst += dst_skip;
  116. }
  117. }
  118. void Painter::fill_rect_with_checkerboard(const Rect& a_rect, const Size& cell_size, Color color_dark, Color color_light)
  119. {
  120. auto rect = a_rect.translated(translation()).intersected(clip_rect());
  121. if (rect.is_empty())
  122. return;
  123. RGBA32* dst = m_target->scanline(rect.top()) + rect.left();
  124. const size_t dst_skip = m_target->pitch() / sizeof(RGBA32);
  125. for (int i = 0; i < rect.height(); ++i) {
  126. for (int j = 0; j < rect.width(); ++j) {
  127. int cell_row = i / cell_size.height();
  128. int cell_col = j / cell_size.width();
  129. dst[j] = ((cell_row % 2) ^ (cell_col % 2)) ? color_light.value() : color_dark.value();
  130. }
  131. dst += dst_skip;
  132. }
  133. }
  134. void Painter::fill_rect_with_gradient(Orientation orientation, const Rect& a_rect, Color gradient_start, Color gradient_end)
  135. {
  136. #ifdef NO_FPU
  137. return fill_rect(a_rect, gradient_start);
  138. #endif
  139. auto rect = a_rect.translated(translation());
  140. auto clipped_rect = Rect::intersection(rect, clip_rect());
  141. if (clipped_rect.is_empty())
  142. return;
  143. int offset = clipped_rect.primary_offset_for_orientation(orientation) - rect.primary_offset_for_orientation(orientation);
  144. RGBA32* dst = m_target->scanline(clipped_rect.top()) + clipped_rect.left();
  145. const size_t dst_skip = m_target->pitch() / sizeof(RGBA32);
  146. float increment = (1.0 / ((rect.primary_size_for_orientation(orientation)) / 255.0));
  147. int r2 = gradient_start.red();
  148. int g2 = gradient_start.green();
  149. int b2 = gradient_start.blue();
  150. int r1 = gradient_end.red();
  151. int g1 = gradient_end.green();
  152. int b1 = gradient_end.blue();
  153. if (orientation == Orientation::Horizontal) {
  154. for (int i = clipped_rect.height() - 1; i >= 0; --i) {
  155. float c = offset * increment;
  156. for (int j = 0; j < clipped_rect.width(); ++j) {
  157. dst[j] = Color(
  158. r1 / 255.0 * c + r2 / 255.0 * (255 - c),
  159. g1 / 255.0 * c + g2 / 255.0 * (255 - c),
  160. b1 / 255.0 * c + b2 / 255.0 * (255 - c))
  161. .value();
  162. c += increment;
  163. }
  164. dst += dst_skip;
  165. }
  166. } else {
  167. float c = offset * increment;
  168. for (int i = clipped_rect.height() - 1; i >= 0; --i) {
  169. Color color(
  170. r1 / 255.0 * c + r2 / 255.0 * (255 - c),
  171. g1 / 255.0 * c + g2 / 255.0 * (255 - c),
  172. b1 / 255.0 * c + b2 / 255.0 * (255 - c));
  173. for (int j = 0; j < clipped_rect.width(); ++j) {
  174. dst[j] = color.value();
  175. }
  176. c += increment;
  177. dst += dst_skip;
  178. }
  179. }
  180. }
  181. void Painter::fill_rect_with_gradient(const Rect& a_rect, Color gradient_start, Color gradient_end)
  182. {
  183. return fill_rect_with_gradient(Orientation::Horizontal, a_rect, gradient_start, gradient_end);
  184. }
  185. void Painter::draw_ellipse_intersecting(const Rect& rect, Color color, int thickness)
  186. {
  187. constexpr int number_samples = 100; // FIXME: dynamically work out the number of samples based upon the rect size
  188. double increment = M_PI / number_samples;
  189. auto ellipse_x = [&](double theta) -> int {
  190. return (cos(theta) * rect.width() / sqrt(2)) + rect.center().x();
  191. };
  192. auto ellipse_y = [&](double theta) -> int {
  193. return (sin(theta) * rect.height() / sqrt(2)) + rect.center().y();
  194. };
  195. for (float theta = 0; theta < 2 * M_PI; theta += increment) {
  196. draw_line({ ellipse_x(theta), ellipse_y(theta) }, { ellipse_x(theta + increment), ellipse_y(theta + increment) }, color, thickness);
  197. }
  198. }
  199. void Painter::draw_rect(const Rect& a_rect, Color color, bool rough)
  200. {
  201. Rect rect = a_rect.translated(translation());
  202. auto clipped_rect = rect.intersected(clip_rect());
  203. if (clipped_rect.is_empty())
  204. return;
  205. int min_y = clipped_rect.top();
  206. int max_y = clipped_rect.bottom();
  207. if (rect.top() >= clipped_rect.top() && rect.top() <= clipped_rect.bottom()) {
  208. int start_x = rough ? max(rect.x() + 1, clipped_rect.x()) : clipped_rect.x();
  209. int width = rough ? min(rect.width() - 2, clipped_rect.width()) : clipped_rect.width();
  210. fast_u32_fill(m_target->scanline(rect.top()) + start_x, color.value(), width);
  211. ++min_y;
  212. }
  213. if (rect.bottom() >= clipped_rect.top() && rect.bottom() <= clipped_rect.bottom()) {
  214. int start_x = rough ? max(rect.x() + 1, clipped_rect.x()) : clipped_rect.x();
  215. int width = rough ? min(rect.width() - 2, clipped_rect.width()) : clipped_rect.width();
  216. fast_u32_fill(m_target->scanline(rect.bottom()) + start_x, color.value(), width);
  217. --max_y;
  218. }
  219. bool draw_left_side = rect.left() >= clipped_rect.left();
  220. bool draw_right_side = rect.right() == clipped_rect.right();
  221. if (draw_left_side && draw_right_side) {
  222. // Specialized loop when drawing both sides.
  223. for (int y = min_y; y <= max_y; ++y) {
  224. auto* bits = m_target->scanline(y);
  225. bits[rect.left()] = color.value();
  226. bits[rect.right()] = color.value();
  227. }
  228. } else {
  229. for (int y = min_y; y <= max_y; ++y) {
  230. auto* bits = m_target->scanline(y);
  231. if (draw_left_side)
  232. bits[rect.left()] = color.value();
  233. if (draw_right_side)
  234. bits[rect.right()] = color.value();
  235. }
  236. }
  237. }
  238. void Painter::draw_bitmap(const Point& p, const CharacterBitmap& bitmap, Color color)
  239. {
  240. auto rect = Rect(p, bitmap.size()).translated(translation());
  241. auto clipped_rect = rect.intersected(clip_rect());
  242. if (clipped_rect.is_empty())
  243. return;
  244. const int first_row = clipped_rect.top() - rect.top();
  245. const int last_row = clipped_rect.bottom() - rect.top();
  246. const int first_column = clipped_rect.left() - rect.left();
  247. const int last_column = clipped_rect.right() - rect.left();
  248. RGBA32* dst = m_target->scanline(clipped_rect.y()) + clipped_rect.x();
  249. const size_t dst_skip = m_target->pitch() / sizeof(RGBA32);
  250. const char* bitmap_row = &bitmap.bits()[first_row * bitmap.width() + first_column];
  251. const size_t bitmap_skip = bitmap.width();
  252. for (int row = first_row; row <= last_row; ++row) {
  253. for (int j = 0; j <= (last_column - first_column); ++j) {
  254. char fc = bitmap_row[j];
  255. if (fc == '#')
  256. dst[j] = color.value();
  257. }
  258. bitmap_row += bitmap_skip;
  259. dst += dst_skip;
  260. }
  261. }
  262. void Painter::draw_bitmap(const Point& p, const GlyphBitmap& bitmap, Color color)
  263. {
  264. auto dst_rect = Rect(p, bitmap.size()).translated(translation());
  265. auto clipped_rect = dst_rect.intersected(clip_rect());
  266. if (clipped_rect.is_empty())
  267. return;
  268. const int first_row = clipped_rect.top() - dst_rect.top();
  269. const int last_row = clipped_rect.bottom() - dst_rect.top();
  270. const int first_column = clipped_rect.left() - dst_rect.left();
  271. const int last_column = clipped_rect.right() - dst_rect.left();
  272. RGBA32* dst = m_target->scanline(clipped_rect.y()) + clipped_rect.x();
  273. const size_t dst_skip = m_target->pitch() / sizeof(RGBA32);
  274. for (int row = first_row; row <= last_row; ++row) {
  275. for (int j = 0; j <= (last_column - first_column); ++j) {
  276. if (bitmap.bit_at(j + first_column, row))
  277. dst[j] = color.value();
  278. }
  279. dst += dst_skip;
  280. }
  281. }
  282. void Painter::draw_triangle(const Point& a, const Point& b, const Point& c, Color color)
  283. {
  284. RGBA32 rgba = color.value();
  285. Point p0(a);
  286. Point p1(b);
  287. Point p2(c);
  288. if (p0.y() > p1.y())
  289. swap(p0, p1);
  290. if (p0.y() > p2.y())
  291. swap(p0, p2);
  292. if (p1.y() > p2.y())
  293. swap(p1, p2);
  294. auto clip = clip_rect();
  295. if (p0.y() >= clip.bottom())
  296. return;
  297. if (p2.y() < clip.top())
  298. return;
  299. float dx01 = (float)(p1.x() - p0.x()) / (p1.y() - p0.y());
  300. float dx02 = (float)(p2.x() - p0.x()) / (p2.y() - p0.y());
  301. float dx12 = (float)(p2.x() - p1.x()) / (p2.y() - p1.y());
  302. float x01 = p0.x();
  303. float x02 = p0.x();
  304. int top = p0.y();
  305. if (top < clip.top()) {
  306. x01 += dx01 * (clip.top() - top);
  307. x02 += dx02 * (clip.top() - top);
  308. top = clip.top();
  309. }
  310. for (int y = top; y < p1.y() && y < clip.bottom(); ++y) {
  311. int start = x01 > x02 ? max((int)x02, clip.left()) : max((int)x01, clip.left());
  312. int end = x01 > x02 ? min((int)x01, clip.right()) : min((int)x02, clip.right());
  313. auto* scanline = m_target->scanline(y);
  314. for (int x = start; x < end; x++) {
  315. scanline[x] = rgba;
  316. }
  317. x01 += dx01;
  318. x02 += dx02;
  319. }
  320. x02 = p0.x() + dx02 * (p1.y() - p0.y());
  321. float x12 = p1.x();
  322. top = p1.y();
  323. if (top < clip.top()) {
  324. x02 += dx02 * (clip.top() - top);
  325. x12 += dx12 * (clip.top() - top);
  326. top = clip.top();
  327. }
  328. for (int y = top; y < p2.y() && y < clip.bottom(); ++y) {
  329. int start = x12 > x02 ? max((int)x02, clip.left()) : max((int)x12, clip.left());
  330. int end = x12 > x02 ? min((int)x12, clip.right()) : min((int)x02, clip.right());
  331. auto* scanline = m_target->scanline(y);
  332. for (int x = start; x < end; x++) {
  333. scanline[x] = rgba;
  334. }
  335. x02 += dx02;
  336. x12 += dx12;
  337. }
  338. }
  339. void Painter::blit_scaled(const Rect& dst_rect_raw, const Gfx::Bitmap& source, const Rect& src_rect, float hscale, float vscale)
  340. {
  341. auto dst_rect = Rect(dst_rect_raw.location(), dst_rect_raw.size()).translated(translation());
  342. auto clipped_rect = dst_rect.intersected(clip_rect());
  343. if (clipped_rect.is_empty())
  344. return;
  345. const int first_row = (clipped_rect.top() - dst_rect.top());
  346. const int last_row = (clipped_rect.bottom() - dst_rect.top());
  347. const int first_column = (clipped_rect.left() - dst_rect.left());
  348. RGBA32* dst = m_target->scanline(clipped_rect.y()) + clipped_rect.x();
  349. const size_t dst_skip = m_target->pitch() / sizeof(RGBA32);
  350. int x_start = first_column + src_rect.left();
  351. for (int row = first_row; row <= last_row; ++row) {
  352. int sr = (row + src_rect.top()) * vscale;
  353. if (sr >= source.size().height() || sr < 0) {
  354. dst += dst_skip;
  355. continue;
  356. }
  357. const RGBA32* sl = source.scanline(sr);
  358. for (int x = x_start; x < clipped_rect.width() + x_start; ++x) {
  359. int sx = x * hscale;
  360. if (sx < source.size().width() && sx >= 0)
  361. dst[x - x_start] = sl[sx];
  362. }
  363. dst += dst_skip;
  364. }
  365. return;
  366. }
  367. void Painter::blit_with_opacity(const Point& position, const Gfx::Bitmap& source, const Rect& src_rect, float opacity)
  368. {
  369. ASSERT(!m_target->has_alpha_channel());
  370. if (!opacity)
  371. return;
  372. if (opacity >= 1.0f)
  373. return blit(position, source, src_rect);
  374. u8 alpha = 255 * opacity;
  375. Rect safe_src_rect = Rect::intersection(src_rect, source.rect());
  376. Rect dst_rect(position, safe_src_rect.size());
  377. dst_rect.move_by(state().translation);
  378. auto clipped_rect = Rect::intersection(dst_rect, clip_rect());
  379. if (clipped_rect.is_empty())
  380. return;
  381. const int first_row = clipped_rect.top() - dst_rect.top();
  382. const int last_row = clipped_rect.bottom() - dst_rect.top();
  383. const int first_column = clipped_rect.left() - dst_rect.left();
  384. const int last_column = clipped_rect.right() - dst_rect.left();
  385. RGBA32* dst = m_target->scanline(clipped_rect.y()) + clipped_rect.x();
  386. const RGBA32* src = source.scanline(src_rect.top() + first_row) + src_rect.left() + first_column;
  387. const size_t dst_skip = m_target->pitch() / sizeof(RGBA32);
  388. const unsigned src_skip = source.pitch() / sizeof(RGBA32);
  389. for (int row = first_row; row <= last_row; ++row) {
  390. for (int x = 0; x <= (last_column - first_column); ++x) {
  391. Color src_color_with_alpha = Color::from_rgb(src[x]);
  392. src_color_with_alpha.set_alpha(alpha);
  393. Color dst_color = Color::from_rgb(dst[x]);
  394. dst[x] = dst_color.blend(src_color_with_alpha).value();
  395. }
  396. dst += dst_skip;
  397. src += src_skip;
  398. }
  399. }
  400. void Painter::blit_filtered(const Point& position, const Gfx::Bitmap& source, const Rect& src_rect, Function<Color(Color)> filter)
  401. {
  402. Rect safe_src_rect = src_rect.intersected(source.rect());
  403. auto dst_rect = Rect(position, safe_src_rect.size()).translated(translation());
  404. auto clipped_rect = dst_rect.intersected(clip_rect());
  405. if (clipped_rect.is_empty())
  406. return;
  407. const int first_row = clipped_rect.top() - dst_rect.top();
  408. const int last_row = clipped_rect.bottom() - dst_rect.top();
  409. const int first_column = clipped_rect.left() - dst_rect.left();
  410. const int last_column = clipped_rect.right() - dst_rect.left();
  411. RGBA32* dst = m_target->scanline(clipped_rect.y()) + clipped_rect.x();
  412. const RGBA32* src = source.scanline(src_rect.top() + first_row) + src_rect.left() + first_column;
  413. const size_t dst_skip = m_target->pitch() / sizeof(RGBA32);
  414. const size_t src_skip = source.pitch() / sizeof(RGBA32);
  415. for (int row = first_row; row <= last_row; ++row) {
  416. for (int x = 0; x <= (last_column - first_column); ++x) {
  417. u8 alpha = Color::from_rgba(src[x]).alpha();
  418. if (alpha == 0xff)
  419. dst[x] = filter(Color::from_rgba(src[x])).value();
  420. else if (!alpha)
  421. continue;
  422. else
  423. dst[x] = Color::from_rgba(dst[x]).blend(filter(Color::from_rgba(src[x]))).value();
  424. }
  425. dst += dst_skip;
  426. src += src_skip;
  427. }
  428. }
  429. void Painter::blit_brightened(const Point& position, const Gfx::Bitmap& source, const Rect& src_rect)
  430. {
  431. return blit_filtered(position, source, src_rect, [](Color src) {
  432. return src.lightened();
  433. });
  434. }
  435. void Painter::blit_dimmed(const Point& position, const Gfx::Bitmap& source, const Rect& src_rect)
  436. {
  437. return blit_filtered(position, source, src_rect, [](Color src) {
  438. return src.to_grayscale().lightened();
  439. });
  440. }
  441. void Painter::draw_tiled_bitmap(const Rect& a_dst_rect, const Gfx::Bitmap& source)
  442. {
  443. auto dst_rect = a_dst_rect.translated(translation());
  444. auto clipped_rect = dst_rect.intersected(clip_rect());
  445. if (clipped_rect.is_empty())
  446. return;
  447. const int first_row = (clipped_rect.top() - dst_rect.top());
  448. const int last_row = (clipped_rect.bottom() - dst_rect.top());
  449. const int first_column = (clipped_rect.left() - dst_rect.left());
  450. RGBA32* dst = m_target->scanline(clipped_rect.y()) + clipped_rect.x();
  451. const size_t dst_skip = m_target->pitch() / sizeof(RGBA32);
  452. if (source.format() == BitmapFormat::RGB32 || source.format() == BitmapFormat::RGBA32) {
  453. int x_start = first_column + a_dst_rect.left();
  454. for (int row = first_row; row <= last_row; ++row) {
  455. const RGBA32* sl = source.scanline((row + a_dst_rect.top())
  456. % source.size().height());
  457. for (int x = x_start; x < clipped_rect.width() + x_start; ++x) {
  458. dst[x - x_start] = sl[x % source.size().width()];
  459. }
  460. dst += dst_skip;
  461. }
  462. return;
  463. }
  464. ASSERT_NOT_REACHED();
  465. }
  466. void Painter::blit_offset(const Point& position,
  467. const Gfx::Bitmap& source,
  468. const Rect& src_rect,
  469. const Point& offset)
  470. {
  471. auto dst_rect = Rect(position, src_rect.size()).translated(translation());
  472. auto clipped_rect = dst_rect.intersected(clip_rect());
  473. if (clipped_rect.is_empty())
  474. return;
  475. const int first_row = (clipped_rect.top() - dst_rect.top());
  476. const int last_row = (clipped_rect.bottom() - dst_rect.top());
  477. const int first_column = (clipped_rect.left() - dst_rect.left());
  478. RGBA32* dst = m_target->scanline(clipped_rect.y()) + clipped_rect.x();
  479. const size_t dst_skip = m_target->pitch() / sizeof(RGBA32);
  480. if (source.format() == BitmapFormat::RGB32 || source.format() == BitmapFormat::RGBA32) {
  481. int x_start = first_column + src_rect.left();
  482. for (int row = first_row; row <= last_row; ++row) {
  483. int sr = row - offset.y() + src_rect.top();
  484. if (sr >= source.size().height() || sr < 0) {
  485. dst += dst_skip;
  486. continue;
  487. }
  488. const RGBA32* sl = source.scanline(sr);
  489. for (int x = x_start; x < clipped_rect.width() + x_start; ++x) {
  490. int sx = x - offset.x();
  491. if (sx < source.size().width() && sx >= 0)
  492. dst[x - x_start] = sl[sx];
  493. }
  494. dst += dst_skip;
  495. }
  496. return;
  497. }
  498. ASSERT_NOT_REACHED();
  499. }
  500. void Painter::blit_with_alpha(const Point& position, const Gfx::Bitmap& source, const Rect& src_rect)
  501. {
  502. ASSERT(source.has_alpha_channel());
  503. Rect safe_src_rect = src_rect.intersected(source.rect());
  504. auto dst_rect = Rect(position, safe_src_rect.size()).translated(translation());
  505. auto clipped_rect = dst_rect.intersected(clip_rect());
  506. if (clipped_rect.is_empty())
  507. return;
  508. const int first_row = clipped_rect.top() - dst_rect.top();
  509. const int last_row = clipped_rect.bottom() - dst_rect.top();
  510. const int first_column = clipped_rect.left() - dst_rect.left();
  511. const int last_column = clipped_rect.right() - dst_rect.left();
  512. RGBA32* dst = m_target->scanline(clipped_rect.y()) + clipped_rect.x();
  513. const RGBA32* src = source.scanline(src_rect.top() + first_row) + src_rect.left() + first_column;
  514. const size_t dst_skip = m_target->pitch() / sizeof(RGBA32);
  515. const size_t src_skip = source.pitch() / sizeof(RGBA32);
  516. for (int row = first_row; row <= last_row; ++row) {
  517. for (int x = 0; x <= (last_column - first_column); ++x) {
  518. u8 alpha = Color::from_rgba(src[x]).alpha();
  519. if (alpha == 0xff)
  520. dst[x] = src[x];
  521. else if (!alpha)
  522. continue;
  523. else
  524. dst[x] = Color::from_rgba(dst[x]).blend(Color::from_rgba(src[x])).value();
  525. }
  526. dst += dst_skip;
  527. src += src_skip;
  528. }
  529. }
  530. void Painter::blit(const Point& position, const Gfx::Bitmap& source, const Rect& src_rect, float opacity)
  531. {
  532. if (opacity < 1.0f)
  533. return blit_with_opacity(position, source, src_rect, opacity);
  534. if (source.has_alpha_channel())
  535. return blit_with_alpha(position, source, src_rect);
  536. auto safe_src_rect = src_rect.intersected(source.rect());
  537. ASSERT(source.rect().contains(safe_src_rect));
  538. auto dst_rect = Rect(position, safe_src_rect.size()).translated(translation());
  539. auto clipped_rect = dst_rect.intersected(clip_rect());
  540. if (clipped_rect.is_empty())
  541. return;
  542. const int first_row = clipped_rect.top() - dst_rect.top();
  543. const int last_row = clipped_rect.bottom() - dst_rect.top();
  544. const int first_column = clipped_rect.left() - dst_rect.left();
  545. RGBA32* dst = m_target->scanline(clipped_rect.y()) + clipped_rect.x();
  546. const size_t dst_skip = m_target->pitch() / sizeof(RGBA32);
  547. if (source.format() == BitmapFormat::RGB32 || source.format() == BitmapFormat::RGBA32) {
  548. const RGBA32* src = source.scanline(src_rect.top() + first_row) + src_rect.left() + first_column;
  549. const size_t src_skip = source.pitch() / sizeof(RGBA32);
  550. for (int row = first_row; row <= last_row; ++row) {
  551. fast_u32_copy(dst, src, clipped_rect.width());
  552. dst += dst_skip;
  553. src += src_skip;
  554. }
  555. return;
  556. }
  557. if (source.format() == BitmapFormat::Indexed8) {
  558. const u8* src = source.bits(src_rect.top() + first_row) + src_rect.left() + first_column;
  559. const size_t src_skip = source.pitch();
  560. for (int row = first_row; row <= last_row; ++row) {
  561. for (int i = 0; i < clipped_rect.width(); ++i)
  562. dst[i] = source.palette_color(src[i]).value();
  563. dst += dst_skip;
  564. src += src_skip;
  565. }
  566. return;
  567. }
  568. ASSERT_NOT_REACHED();
  569. }
  570. template<bool has_alpha_channel, typename GetPixel>
  571. ALWAYS_INLINE static void do_draw_integer_scaled_bitmap(Gfx::Bitmap& target, const Rect& dst_rect, const Gfx::Bitmap& source, int hfactor, int vfactor, GetPixel get_pixel)
  572. {
  573. for (int y = source.rect().top(); y <= source.rect().bottom(); ++y) {
  574. int dst_y = dst_rect.y() + y * vfactor;
  575. for (int x = source.rect().left(); x <= source.rect().right(); ++x) {
  576. auto src_pixel = get_pixel(source, x, y);
  577. for (int yo = 0; yo < vfactor; ++yo) {
  578. auto* scanline = (Color*)target.scanline(dst_y + yo);
  579. int dst_x = dst_rect.x() + x * hfactor;
  580. for (int xo = 0; xo < hfactor; ++xo) {
  581. if constexpr (has_alpha_channel)
  582. scanline[dst_x + xo] = scanline[dst_x + xo].blend(src_pixel);
  583. else
  584. scanline[dst_x + xo] = src_pixel;
  585. }
  586. }
  587. }
  588. }
  589. }
  590. template<bool has_alpha_channel, typename GetPixel>
  591. ALWAYS_INLINE static void do_draw_scaled_bitmap(Gfx::Bitmap& target, const Rect& dst_rect, const Rect& clipped_rect, const Gfx::Bitmap& source, const Rect& src_rect, int hscale, int vscale, GetPixel get_pixel)
  592. {
  593. if (dst_rect == clipped_rect && !(dst_rect.width() % src_rect.width()) && !(dst_rect.height() % src_rect.height())) {
  594. int hfactor = dst_rect.width() / src_rect.width();
  595. int vfactor = dst_rect.height() / src_rect.height();
  596. if (hfactor == 2 && vfactor == 2)
  597. return do_draw_integer_scaled_bitmap<has_alpha_channel>(target, dst_rect, source, 2, 2, get_pixel);
  598. if (hfactor == 3 && vfactor == 3)
  599. return do_draw_integer_scaled_bitmap<has_alpha_channel>(target, dst_rect, source, 3, 3, get_pixel);
  600. if (hfactor == 4 && vfactor == 4)
  601. return do_draw_integer_scaled_bitmap<has_alpha_channel>(target, dst_rect, source, 4, 4, get_pixel);
  602. return do_draw_integer_scaled_bitmap<has_alpha_channel>(target, dst_rect, source, hfactor, vfactor, get_pixel);
  603. }
  604. for (int y = clipped_rect.top(); y <= clipped_rect.bottom(); ++y) {
  605. auto* scanline = (Color*)target.scanline(y);
  606. for (int x = clipped_rect.left(); x <= clipped_rect.right(); ++x) {
  607. auto scaled_x = ((x - dst_rect.x()) * hscale) >> 16;
  608. auto scaled_y = ((y - dst_rect.y()) * vscale) >> 16;
  609. auto src_pixel = get_pixel(source, scaled_x, scaled_y);
  610. if constexpr (has_alpha_channel) {
  611. scanline[x] = scanline[x].blend(src_pixel);
  612. } else
  613. scanline[x] = src_pixel;
  614. }
  615. }
  616. }
  617. void Painter::draw_scaled_bitmap(const Rect& a_dst_rect, const Gfx::Bitmap& source, const Rect& src_rect)
  618. {
  619. auto dst_rect = a_dst_rect;
  620. if (dst_rect.size() == src_rect.size())
  621. return blit(dst_rect.location(), source, src_rect);
  622. auto safe_src_rect = src_rect.intersected(source.rect());
  623. ASSERT(source.rect().contains(safe_src_rect));
  624. dst_rect.move_by(state().translation);
  625. auto clipped_rect = dst_rect.intersected(clip_rect());
  626. if (clipped_rect.is_empty())
  627. return;
  628. int hscale = (src_rect.width() << 16) / dst_rect.width();
  629. int vscale = (src_rect.height() << 16) / dst_rect.height();
  630. if (source.has_alpha_channel()) {
  631. switch (source.format()) {
  632. case BitmapFormat::RGB32:
  633. do_draw_scaled_bitmap<true>(*m_target, dst_rect, clipped_rect, source, src_rect, hscale, vscale, get_pixel<BitmapFormat::RGB32>);
  634. break;
  635. case BitmapFormat::RGBA32:
  636. do_draw_scaled_bitmap<true>(*m_target, dst_rect, clipped_rect, source, src_rect, hscale, vscale, get_pixel<BitmapFormat::RGBA32>);
  637. break;
  638. case BitmapFormat::Indexed8:
  639. do_draw_scaled_bitmap<true>(*m_target, dst_rect, clipped_rect, source, src_rect, hscale, vscale, get_pixel<BitmapFormat::Indexed8>);
  640. break;
  641. default:
  642. do_draw_scaled_bitmap<true>(*m_target, dst_rect, clipped_rect, source, src_rect, hscale, vscale, get_pixel<BitmapFormat::Invalid>);
  643. break;
  644. }
  645. } else {
  646. switch (source.format()) {
  647. case BitmapFormat::RGB32:
  648. do_draw_scaled_bitmap<false>(*m_target, dst_rect, clipped_rect, source, src_rect, hscale, vscale, get_pixel<BitmapFormat::RGB32>);
  649. break;
  650. case BitmapFormat::RGBA32:
  651. do_draw_scaled_bitmap<false>(*m_target, dst_rect, clipped_rect, source, src_rect, hscale, vscale, get_pixel<BitmapFormat::RGBA32>);
  652. break;
  653. case BitmapFormat::Indexed8:
  654. do_draw_scaled_bitmap<false>(*m_target, dst_rect, clipped_rect, source, src_rect, hscale, vscale, get_pixel<BitmapFormat::Indexed8>);
  655. break;
  656. default:
  657. do_draw_scaled_bitmap<false>(*m_target, dst_rect, clipped_rect, source, src_rect, hscale, vscale, get_pixel<BitmapFormat::Invalid>);
  658. break;
  659. }
  660. }
  661. }
  662. FLATTEN void Painter::draw_glyph(const Point& point, char ch, Color color)
  663. {
  664. draw_glyph(point, ch, font(), color);
  665. }
  666. FLATTEN void Painter::draw_glyph(const Point& point, char ch, const Font& font, Color color)
  667. {
  668. draw_bitmap(point, font.glyph_bitmap(ch), color);
  669. }
  670. void Painter::draw_emoji(const Point& point, const Gfx::Bitmap& emoji, const Font& font)
  671. {
  672. if (!font.is_fixed_width())
  673. blit(point, emoji, emoji.rect());
  674. else {
  675. Rect dst_rect {
  676. point.x(),
  677. point.y(),
  678. font.glyph_width('x'),
  679. font.glyph_height()
  680. };
  681. draw_scaled_bitmap(dst_rect, emoji, emoji.rect());
  682. }
  683. }
  684. void Painter::draw_glyph_or_emoji(const Point& point, u32 codepoint, const Font& font, Color color)
  685. {
  686. if (codepoint < 256) {
  687. // This looks like a regular character.
  688. draw_glyph(point, (char)codepoint, font, color);
  689. return;
  690. }
  691. // Perhaps it's an emoji?
  692. auto* emoji = Emoji::emoji_for_codepoint(codepoint);
  693. if (emoji == nullptr) {
  694. #ifdef EMOJI_DEBUG
  695. dbg() << "Failed to find an emoji for codepoint " << codepoint;
  696. #endif
  697. draw_glyph(point, '?', font, color);
  698. return;
  699. }
  700. draw_emoji(point, *emoji, font);
  701. }
  702. void Painter::draw_text_line(const Rect& a_rect, const Utf8View& text, const Font& font, TextAlignment alignment, Color color, TextElision elision)
  703. {
  704. auto rect = a_rect;
  705. Utf8View final_text(text);
  706. String elided_text;
  707. if (elision == TextElision::Right) {
  708. int text_width = font.width(final_text);
  709. if (font.width(final_text) > rect.width()) {
  710. int glyph_spacing = font.glyph_spacing();
  711. int byte_offset = 0;
  712. int new_width = font.width("...");
  713. if (new_width < text_width) {
  714. for (auto it = final_text.begin(); it != final_text.end(); ++it) {
  715. u32 codepoint = *it;
  716. int glyph_width = font.glyph_or_emoji_width(codepoint);
  717. // NOTE: Glyph spacing should not be added after the last glyph on the line,
  718. // but since we are here because the last glyph does not actually fit on the line,
  719. // we don't have to worry about spacing.
  720. int width_with_this_glyph_included = new_width + glyph_width + glyph_spacing;
  721. if (width_with_this_glyph_included > rect.width())
  722. break;
  723. byte_offset = final_text.byte_offset_of(it);
  724. new_width += glyph_width + glyph_spacing;
  725. }
  726. StringBuilder builder;
  727. builder.append(final_text.substring_view(0, byte_offset).as_string());
  728. builder.append("...");
  729. elided_text = builder.to_string();
  730. final_text = Utf8View { elided_text };
  731. }
  732. }
  733. }
  734. switch (alignment) {
  735. case TextAlignment::TopLeft:
  736. case TextAlignment::CenterLeft:
  737. break;
  738. case TextAlignment::TopRight:
  739. case TextAlignment::CenterRight:
  740. rect.set_x(rect.right() - font.width(final_text));
  741. break;
  742. case TextAlignment::Center: {
  743. auto shrunken_rect = rect;
  744. shrunken_rect.set_width(font.width(final_text));
  745. shrunken_rect.center_within(rect);
  746. rect = shrunken_rect;
  747. break;
  748. }
  749. default:
  750. ASSERT_NOT_REACHED();
  751. }
  752. auto point = rect.location();
  753. int space_width = font.glyph_width(' ') + font.glyph_spacing();
  754. for (u32 codepoint : final_text) {
  755. if (codepoint == ' ') {
  756. point.move_by(space_width, 0);
  757. continue;
  758. }
  759. draw_glyph_or_emoji(point, codepoint, font, color);
  760. point.move_by(font.glyph_or_emoji_width(codepoint) + font.glyph_spacing(), 0);
  761. }
  762. }
  763. void Painter::draw_text(const Rect& rect, const StringView& text, TextAlignment alignment, Color color, TextElision elision)
  764. {
  765. draw_text(rect, text, font(), alignment, color, elision);
  766. }
  767. void Painter::draw_text(const Rect& rect, const StringView& raw_text, const Font& font, TextAlignment alignment, Color color, TextElision elision)
  768. {
  769. Utf8View text { raw_text };
  770. Vector<Utf8View, 32> lines;
  771. int start_of_current_line = 0;
  772. for (auto it = text.begin(); it != text.end(); ++it) {
  773. u32 codepoint = *it;
  774. if (codepoint == '\n') {
  775. int byte_offset = text.byte_offset_of(it);
  776. Utf8View line = text.substring_view(start_of_current_line, byte_offset - start_of_current_line);
  777. lines.append(line);
  778. start_of_current_line = byte_offset + 1;
  779. }
  780. }
  781. if (start_of_current_line != text.byte_length()) {
  782. Utf8View line = text.substring_view(start_of_current_line, text.byte_length() - start_of_current_line);
  783. lines.append(line);
  784. }
  785. static const int line_spacing = 4;
  786. int line_height = font.glyph_height() + line_spacing;
  787. Rect bounding_rect { 0, 0, 0, (static_cast<int>(lines.size()) * line_height) - line_spacing };
  788. for (auto& line : lines) {
  789. auto line_width = font.width(line);
  790. if (line_width > bounding_rect.width())
  791. bounding_rect.set_width(line_width);
  792. }
  793. switch (alignment) {
  794. case TextAlignment::TopLeft:
  795. bounding_rect.set_location(rect.location());
  796. break;
  797. case TextAlignment::TopRight:
  798. bounding_rect.set_location({ (rect.right() + 1) - bounding_rect.width(), rect.y() });
  799. break;
  800. case TextAlignment::CenterLeft:
  801. bounding_rect.set_location({ rect.x(), rect.center().y() - (bounding_rect.height() / 2) });
  802. break;
  803. case TextAlignment::CenterRight:
  804. bounding_rect.set_location({ (rect.right() + 1) - bounding_rect.width(), rect.center().y() - (bounding_rect.height() / 2) });
  805. break;
  806. case TextAlignment::Center:
  807. bounding_rect.center_within(rect);
  808. break;
  809. default:
  810. ASSERT_NOT_REACHED();
  811. }
  812. for (size_t i = 0; i < lines.size(); ++i) {
  813. auto& line = lines[i];
  814. Rect line_rect { bounding_rect.x(), bounding_rect.y() + static_cast<int>(i) * line_height, bounding_rect.width(), line_height };
  815. line_rect.intersect(rect);
  816. draw_text_line(line_rect, line, font, alignment, color, elision);
  817. }
  818. }
  819. void Painter::set_pixel(const Point& p, Color color)
  820. {
  821. auto point = p;
  822. point.move_by(state().translation);
  823. if (!clip_rect().contains(point))
  824. return;
  825. m_target->scanline(point.y())[point.x()] = color.value();
  826. }
  827. ALWAYS_INLINE void Painter::set_pixel_with_draw_op(u32& pixel, const Color& color)
  828. {
  829. if (draw_op() == DrawOp::Copy)
  830. pixel = color.value();
  831. else if (draw_op() == DrawOp::Xor)
  832. pixel ^= color.value();
  833. }
  834. void Painter::draw_pixel(const Point& position, Color color, int thickness)
  835. {
  836. ASSERT(draw_op() == DrawOp::Copy);
  837. if (thickness == 1)
  838. return set_pixel_with_draw_op(m_target->scanline(position.y())[position.x()], color);
  839. Rect rect { position.translated(-(thickness / 2), -(thickness / 2)), { thickness, thickness } };
  840. fill_rect(rect.translated(-state().translation), color);
  841. }
  842. void Painter::draw_line(const Point& p1, const Point& p2, Color color, int thickness, bool dotted)
  843. {
  844. auto clip_rect = this->clip_rect();
  845. auto point1 = p1;
  846. point1.move_by(state().translation);
  847. auto point2 = p2;
  848. point2.move_by(state().translation);
  849. // Special case: vertical line.
  850. if (point1.x() == point2.x()) {
  851. const int x = point1.x();
  852. if (x < clip_rect.left() || x > clip_rect.right())
  853. return;
  854. if (point1.y() > point2.y())
  855. swap(point1, point2);
  856. if (point1.y() > clip_rect.bottom())
  857. return;
  858. if (point2.y() < clip_rect.top())
  859. return;
  860. int min_y = max(point1.y(), clip_rect.top());
  861. int max_y = min(point2.y(), clip_rect.bottom());
  862. if (dotted) {
  863. for (int y = min_y; y <= max_y; y += 2)
  864. draw_pixel({ x, y }, color, thickness);
  865. } else {
  866. for (int y = min_y; y <= max_y; ++y)
  867. draw_pixel({ x, y }, color, thickness);
  868. }
  869. return;
  870. }
  871. // Special case: horizontal line.
  872. if (point1.y() == point2.y()) {
  873. const int y = point1.y();
  874. if (y < clip_rect.top() || y > clip_rect.bottom())
  875. return;
  876. if (point1.x() > point2.x())
  877. swap(point1, point2);
  878. if (point1.x() > clip_rect.right())
  879. return;
  880. if (point2.x() < clip_rect.left())
  881. return;
  882. int min_x = max(point1.x(), clip_rect.left());
  883. int max_x = min(point2.x(), clip_rect.right());
  884. if (dotted) {
  885. for (int x = min_x; x <= max_x; x += 2)
  886. draw_pixel({ x, y }, color, thickness);
  887. } else {
  888. for (int x = min_x; x <= max_x; ++x)
  889. draw_pixel({ x, y }, color, thickness);
  890. }
  891. return;
  892. }
  893. // FIXME: Implement dotted diagonal lines.
  894. ASSERT(!dotted);
  895. const double adx = abs(point2.x() - point1.x());
  896. const double ady = abs(point2.y() - point1.y());
  897. if (adx > ady) {
  898. if (point1.x() > point2.x())
  899. swap(point1, point2);
  900. } else {
  901. if (point1.y() > point2.y())
  902. swap(point1, point2);
  903. }
  904. // FIXME: Implement clipping below.
  905. const double dx = point2.x() - point1.x();
  906. const double dy = point2.y() - point1.y();
  907. double error = 0;
  908. if (dx > dy) {
  909. const double y_step = dy == 0 ? 0 : (dy > 0 ? 1 : -1);
  910. const double delta_error = fabs(dy / dx);
  911. int y = point1.y();
  912. for (int x = point1.x(); x <= point2.x(); ++x) {
  913. if (clip_rect.contains(x, y))
  914. draw_pixel({ x, y }, color, thickness);
  915. error += delta_error;
  916. if (error >= 0.5) {
  917. y = (double)y + y_step;
  918. error -= 1.0;
  919. }
  920. }
  921. } else {
  922. const double x_step = dx == 0 ? 0 : (dx > 0 ? 1 : -1);
  923. const double delta_error = fabs(dx / dy);
  924. int x = point1.x();
  925. for (int y = point1.y(); y <= point2.y(); ++y) {
  926. if (clip_rect.contains(x, y))
  927. draw_pixel({ x, y }, color, thickness);
  928. error += delta_error;
  929. if (error >= 0.5) {
  930. x = (double)x + x_step;
  931. error -= 1.0;
  932. }
  933. }
  934. }
  935. }
  936. static void split_quadratic_bezier_curve(const FloatPoint& original_control, const FloatPoint& p1, const FloatPoint& p2, Function<void(const FloatPoint&, const FloatPoint&)>& callback)
  937. {
  938. auto po1_midpoint = original_control + p1;
  939. po1_midpoint /= 2;
  940. auto po2_midpoint = original_control + p2;
  941. po2_midpoint /= 2;
  942. auto new_segment = po1_midpoint + po2_midpoint;
  943. new_segment /= 2;
  944. Painter::for_each_line_segment_on_bezier_curve(po1_midpoint, p1, new_segment, callback);
  945. Painter::for_each_line_segment_on_bezier_curve(po2_midpoint, new_segment, p2, callback);
  946. }
  947. static bool can_approximate_bezier_curve(const FloatPoint& p1, const FloatPoint& p2, const FloatPoint& control)
  948. {
  949. constexpr static int tolerance = 15;
  950. auto p1x = 3 * control.x() - 2 * p1.x() - p2.x();
  951. auto p1y = 3 * control.y() - 2 * p1.y() - p2.y();
  952. auto p2x = 3 * control.x() - 2 * p2.x() - p1.x();
  953. auto p2y = 3 * control.y() - 2 * p2.y() - p1.y();
  954. p1x = p1x * p1x;
  955. p1y = p1y * p1y;
  956. p2x = p2x * p2x;
  957. p2y = p2y * p2y;
  958. return max(p1x, p2x) + max(p1y, p2y) <= tolerance;
  959. }
  960. void Painter::for_each_line_segment_on_bezier_curve(const FloatPoint& control_point, const FloatPoint& p1, const FloatPoint& p2, Function<void(const FloatPoint&, const FloatPoint&)>& callback)
  961. {
  962. if (can_approximate_bezier_curve(p1, p2, control_point)) {
  963. callback(p1, p2);
  964. } else {
  965. split_quadratic_bezier_curve(control_point, p1, p2, callback);
  966. }
  967. }
  968. void Painter::for_each_line_segment_on_bezier_curve(const FloatPoint& control_point, const FloatPoint& p1, const FloatPoint& p2, Function<void(const FloatPoint&, const FloatPoint&)>&& callback)
  969. {
  970. for_each_line_segment_on_bezier_curve(control_point, p1, p2, callback);
  971. }
  972. void Painter::draw_quadratic_bezier_curve(const Point& control_point, const Point& p1, const Point& p2, Color color, int thickness, bool dotted)
  973. {
  974. for_each_line_segment_on_bezier_curve(FloatPoint(control_point.x(), control_point.y()), FloatPoint(p1.x(), p1.y()), FloatPoint(p2.x(), p2.y()), [&](const FloatPoint& p1, const FloatPoint& p2) {
  975. draw_line(Point(p1.x(), p1.y()), Point(p2.x(), p2.y()), color, thickness, dotted);
  976. });
  977. }
  978. void Painter::add_clip_rect(const Rect& rect)
  979. {
  980. state().clip_rect.intersect(rect.translated(m_clip_origin.location()));
  981. state().clip_rect.intersect(m_target->rect());
  982. }
  983. void Painter::clear_clip_rect()
  984. {
  985. state().clip_rect = m_clip_origin;
  986. }
  987. PainterStateSaver::PainterStateSaver(Painter& painter)
  988. : m_painter(painter)
  989. {
  990. m_painter.save();
  991. }
  992. PainterStateSaver::~PainterStateSaver()
  993. {
  994. m_painter.restore();
  995. }
  996. void Painter::stroke_path(const Path& path, Color color, int thickness)
  997. {
  998. FloatPoint cursor;
  999. for (auto& segment : path.segments()) {
  1000. switch (segment.type) {
  1001. case Path::Segment::Type::Invalid:
  1002. ASSERT_NOT_REACHED();
  1003. break;
  1004. case Path::Segment::Type::MoveTo:
  1005. cursor = segment.point;
  1006. break;
  1007. case Path::Segment::Type::LineTo:
  1008. draw_line(Point(cursor.x(), cursor.y()), Point(segment.point.x(), segment.point.y()), color, thickness);
  1009. cursor = segment.point;
  1010. break;
  1011. case Path::Segment::Type::QuadraticBezierCurveTo:
  1012. ASSERT(segment.through.has_value());
  1013. draw_quadratic_bezier_curve(Point(segment.through.value().x(), segment.through.value().y()), Point(cursor.x(), cursor.y()), Point(segment.point.x(), segment.point.y()), color, thickness);
  1014. cursor = segment.point;
  1015. break;
  1016. }
  1017. }
  1018. }
  1019. //#define FILL_PATH_DEBUG
  1020. void Painter::fill_path(Path& path, Color color, WindingRule winding_rule)
  1021. {
  1022. const auto& segments = path.split_lines(Path::Simple);
  1023. if (segments.size() == 0)
  1024. return;
  1025. Vector<Path::LineSegment> active_list;
  1026. active_list.ensure_capacity(segments.size());
  1027. // first, grab the segments for the very first scanline
  1028. auto first_y = segments.first().maximum_y;
  1029. auto last_y = segments.last().minimum_y;
  1030. auto scanline = first_y;
  1031. size_t last_active_segment { 0 };
  1032. for (auto& segment : segments) {
  1033. if (segment.maximum_y != scanline)
  1034. break;
  1035. active_list.append(segment);
  1036. ++last_active_segment;
  1037. }
  1038. auto is_inside_shape = [winding_rule](int winding_number) {
  1039. if (winding_rule == WindingRule::Nonzero)
  1040. return winding_number != 0;
  1041. if (winding_rule == WindingRule::EvenOdd)
  1042. return winding_number % 2 == 0;
  1043. ASSERT_NOT_REACHED();
  1044. };
  1045. auto increment_winding = [winding_rule](int& winding_number, const Point& from, const Point& to) {
  1046. if (winding_rule == WindingRule::EvenOdd) {
  1047. ++winding_number;
  1048. return;
  1049. }
  1050. if (winding_rule == WindingRule::Nonzero) {
  1051. if (from.dy_relative_to(to) < 0)
  1052. ++winding_number;
  1053. else
  1054. --winding_number;
  1055. return;
  1056. }
  1057. ASSERT_NOT_REACHED();
  1058. };
  1059. while (scanline >= last_y) {
  1060. if (active_list.size()) {
  1061. // sort the active list by 'x' from right to left
  1062. quick_sort(active_list, [](const auto& line0, const auto& line1) {
  1063. return line1.x < line0.x;
  1064. });
  1065. #ifdef FILL_PATH_DEBUG
  1066. if ((int)scanline % 10 == 0) {
  1067. draw_text(Rect(active_list.last().x - 20, scanline, 20, 10), String::format("%d", (int)scanline));
  1068. }
  1069. #endif
  1070. if (active_list.size() > 1) {
  1071. auto winding_number { 0 };
  1072. for (size_t i = 1; i < active_list.size(); ++i) {
  1073. auto& previous = active_list[i - 1];
  1074. auto& current = active_list[i];
  1075. int int_distance = fabs(current.x - previous.x);
  1076. Point from(previous.x, scanline);
  1077. Point to(current.x, scanline);
  1078. if (int_distance < 1) {
  1079. // the two lines intersect on an int grid
  1080. // so they should both be treated as a single line segment
  1081. goto skip_drawing;
  1082. }
  1083. if (int_distance == 1 && is_inside_shape(winding_number)) {
  1084. // The two lines form a singluar edge for the shape
  1085. // while they do not intersect, they connect together
  1086. goto skip_drawing;
  1087. }
  1088. if (is_inside_shape(winding_number)) {
  1089. // The points between this segment and the previous are
  1090. // inside the shape
  1091. #ifdef FILL_PATH_DEBUG
  1092. dbg() << "y=" << scanline << ": " << winding_number << " at " << i << ": " << from << " -- " << to;
  1093. #endif
  1094. draw_line(from, to, color, 1, false);
  1095. }
  1096. skip_drawing:;
  1097. auto is_passing_through_maxima = scanline == previous.maximum_y
  1098. || scanline == previous.minimum_y
  1099. || scanline == current.maximum_y
  1100. || scanline == current.minimum_y;
  1101. auto is_passing_through_vertex = false;
  1102. if (is_passing_through_maxima) {
  1103. is_passing_through_vertex = previous.x == current.x;
  1104. }
  1105. if (!is_passing_through_vertex || previous.inverse_slope * current.inverse_slope < 0)
  1106. increment_winding(winding_number, from, to);
  1107. // update the x coord
  1108. active_list[i - 1].x -= active_list[i - 1].inverse_slope;
  1109. }
  1110. active_list.last().x -= active_list.last().inverse_slope;
  1111. } else {
  1112. auto point = Point(active_list[0].x, scanline);
  1113. draw_line(point, point, color);
  1114. // update the x coord
  1115. active_list.first().x -= active_list.first().inverse_slope;
  1116. }
  1117. }
  1118. --scanline;
  1119. // remove any edge that goes out of bound from the active list
  1120. for (size_t i = 0, count = active_list.size(); i < count; ++i) {
  1121. if (scanline <= active_list[i].minimum_y) {
  1122. active_list.remove(i);
  1123. --count;
  1124. --i;
  1125. }
  1126. }
  1127. for (size_t j = last_active_segment; j < segments.size(); ++j, ++last_active_segment) {
  1128. auto& segment = segments[j];
  1129. if (segment.maximum_y < scanline)
  1130. break;
  1131. if (segment.minimum_y >= scanline)
  1132. continue;
  1133. active_list.append(segment);
  1134. }
  1135. }
  1136. #ifdef FILL_PATH_DEBUG
  1137. size_t i { 0 };
  1138. for (auto& segment : segments)
  1139. draw_line(segment.from, segment.to, Color::from_hsv(++i / segments.size() * 255, 255, 255), 1);
  1140. #endif
  1141. }
  1142. }