Painter.cpp 48 KB

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