Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

  1. #include "fitz.h"
  2.  
  3. /*
  4.  
  5. The functions in this file implement various flavours of Porter-Duff blending.
  6.  
  7. We take the following as definitions:
  8.  
  9.         Cx = Color (from plane x)
  10.         ax = Alpha (from plane x)
  11.         cx = Cx.ax = Premultiplied color (from plane x)
  12.  
  13. The general PorterDuff blending equation is:
  14.  
  15.         Blend Z = X op Y        cz = Fx.cx + Fy. cy     where Fx and Fy depend on op
  16.  
  17. The two operations we use in this file are: '(X in Y) over Z' and
  18. 'S over Z'. The definitions of the 'over' and 'in' operations are as
  19. follows:
  20.  
  21.         For S over Z,   Fs = 1, Fz = 1-as
  22.         For X in Y,     Fx = ay, Fy = 0
  23.  
  24. We have 2 choices; we can either work with premultiplied data, or non
  25. premultiplied data. Our
  26.  
  27. First the premultiplied case:
  28.  
  29.         Let S = (X in Y)
  30.         Let R = (X in Y) over Z = S over Z
  31.  
  32.         cs      = cx.Fx + cy.Fy (where Fx = ay, Fy = 0)
  33.                 = cx.ay
  34.         as      = ax.Fx + ay.Fy
  35.                 = ax.ay
  36.  
  37.         cr      = cs.Fs + cz.Fz (where Fs = 1, Fz = 1-as)
  38.                 = cs + cz.(1-as)
  39.                 = cx.ay + cz.(1-ax.ay)
  40.         ar      = as.Fs + az.Fz
  41.                 = as + az.(1-as)
  42.                 = ax.ay + az.(1-ax.ay)
  43.  
  44. This has various nice properties, like not needing any divisions, and
  45. being symmetric in color and alpha, so this is what we use. Because we
  46. went through the pain of deriving the non premultiplied forms, we list
  47. them here too, though they are not used.
  48.  
  49. Non Pre-multiplied case:
  50.  
  51.         Cs.as   = Fx.Cx.ax + Fy.Cy.ay   (where Fx = ay, Fy = 0)
  52.                 = Cx.ay.ax
  53.         Cs      = (Cx.ay.ax)/(ay.ax)
  54.                 = Cx
  55.         Cr.ar   = Fs.Cs.as + Fz.Cz.az   (where Fs = 1, Fz = 1-as)
  56.                 = Cs.as + (1-as).Cz.az
  57.                 = Cx.ax.ay + Cz.az.(1-ax.ay)
  58.         Cr      = (Cx.ax.ay + Cz.az.(1-ax.ay))/(ax.ay + az.(1-ax-ay))
  59.  
  60. Much more complex, it seems. However, if we could restrict ourselves to
  61. the case where we were always plotting onto an opaque background (i.e.
  62. az = 1), then:
  63.  
  64.         Cr      = Cx.(ax.ay) + Cz.(1-ax.ay)
  65.                 = (Cx-Cz)*(1-ax.ay) + Cz        (a single MLA operation)
  66.         ar      = 1
  67.  
  68. Sadly, this is not true in the general case, so we abandon this effort
  69. and stick to using the premultiplied form.
  70.  
  71. */
  72.  
  73. typedef unsigned char byte;
  74.  
  75. /* These are used by the non-aa scan converter */
  76.  
  77. void
  78. fz_paint_solid_alpha(byte * restrict dp, int w, int alpha)
  79. {
  80.         int t = FZ_EXPAND(255 - alpha);
  81.         while (w--)
  82.         {
  83.                 *dp = alpha + FZ_COMBINE(*dp, t);
  84.                 dp ++;
  85.         }
  86. }
  87.  
  88. void
  89. fz_paint_solid_color(byte * restrict dp, int n, int w, byte *color)
  90. {
  91.         int n1 = n - 1;
  92.         int sa = FZ_EXPAND(color[n1]);
  93.         int k;
  94.         while (w--)
  95.         {
  96.                 int ma = FZ_COMBINE(FZ_EXPAND(255), sa);
  97.                 for (k = 0; k < n1; k++)
  98.                         dp[k] = FZ_BLEND(color[k], dp[k], ma);
  99.                 dp[k] = FZ_BLEND(255, dp[k], ma);
  100.                 dp += n;
  101.         }
  102. }
  103.  
  104. /* Blend a non-premultiplied color in mask over destination */
  105.  
  106. static inline void
  107. fz_paint_span_with_color_2(byte * restrict dp, byte * restrict mp, int w, byte *color)
  108. {
  109.         int sa = FZ_EXPAND(color[1]);
  110.         int g = color[0];
  111.         while (w--)
  112.         {
  113.                 int ma = *mp++;
  114.                 ma = FZ_COMBINE(FZ_EXPAND(ma), sa);
  115.                 dp[0] = FZ_BLEND(g, dp[0], ma);
  116.                 dp[1] = FZ_BLEND(255, dp[1], ma);
  117.                 dp += 2;
  118.         }
  119. }
  120.  
  121. static inline void
  122. fz_paint_span_with_color_4(byte * restrict dp, byte * restrict mp, int w, byte *color)
  123. {
  124.         int sa = FZ_EXPAND(color[3]);
  125.         int r = color[0];
  126.         int g = color[1];
  127.         int b = color[2];
  128.         while (w--)
  129.         {
  130.                 int ma = *mp++;
  131.                 ma = FZ_COMBINE(FZ_EXPAND(ma), sa);
  132.                 dp[0] = FZ_BLEND(r, dp[0], ma);
  133.                 dp[1] = FZ_BLEND(g, dp[1], ma);
  134.                 dp[2] = FZ_BLEND(b, dp[2], ma);
  135.                 dp[3] = FZ_BLEND(255, dp[3], ma);
  136.                 dp += 4;
  137.         }
  138. }
  139.  
  140. static inline void
  141. fz_paint_span_with_color_N(byte * restrict dp, byte * restrict mp, int n, int w, byte *color)
  142. {
  143.         int n1 = n - 1;
  144.         int sa = FZ_EXPAND(color[n1]);
  145.         int k;
  146.         while (w--)
  147.         {
  148.                 int ma = *mp++;
  149.                 ma = FZ_COMBINE(FZ_EXPAND(ma), sa);
  150.                 for (k = 0; k < n1; k++)
  151.                         dp[k] = FZ_BLEND(color[k], dp[k], ma);
  152.                 dp[k] = FZ_BLEND(255, dp[k], ma);
  153.                 dp += n;
  154.         }
  155. }
  156.  
  157. void
  158. fz_paint_span_with_color(byte * restrict dp, byte * restrict mp, int n, int w, byte *color)
  159. {
  160.         switch (n)
  161.         {
  162.         case 2: fz_paint_span_with_color_2(dp, mp, w, color); break;
  163.         case 4: fz_paint_span_with_color_4(dp, mp, w, color); break;
  164.         default: fz_paint_span_with_color_N(dp, mp, n, w, color); break;
  165.         }
  166. }
  167.  
  168. /* Blend source in mask over destination */
  169.  
  170. static inline void
  171. fz_paint_span_with_mask_2(byte * restrict dp, byte * restrict sp, byte * restrict mp, int w)
  172. {
  173.         while (w--)
  174.         {
  175.                 int masa;
  176.                 int ma = *mp++;
  177.                 ma = FZ_EXPAND(ma);
  178.                 masa = FZ_COMBINE(sp[1], ma);
  179.                 masa = 255 - masa;
  180.                 masa = FZ_EXPAND(masa);
  181.                 *dp = FZ_COMBINE2(*sp, ma, *dp, masa);
  182.                 sp++; dp++;
  183.                 *dp = FZ_COMBINE2(*sp, ma, *dp, masa);
  184.                 sp++; dp++;
  185.         }
  186. }
  187.  
  188. static inline void
  189. fz_paint_span_with_mask_4(byte * restrict dp, byte * restrict sp, byte * restrict mp, int w)
  190. {
  191.         while (w--)
  192.         {
  193.                 int masa;
  194.                 int ma = *mp++;
  195.                 ma = FZ_EXPAND(ma);
  196.                 masa = FZ_COMBINE(sp[3], ma);
  197.                 masa = 255 - masa;
  198.                 masa = FZ_EXPAND(masa);
  199.                 *dp = FZ_COMBINE2(*sp, ma, *dp, masa);
  200.                 sp++; dp++;
  201.                 *dp = FZ_COMBINE2(*sp, ma, *dp, masa);
  202.                 sp++; dp++;
  203.                 *dp = FZ_COMBINE2(*sp, ma, *dp, masa);
  204.                 sp++; dp++;
  205.                 *dp = FZ_COMBINE2(*sp, ma, *dp, masa);
  206.                 sp++; dp++;
  207.         }
  208. }
  209.  
  210. static inline void
  211. fz_paint_span_with_mask_N(byte * restrict dp, byte * restrict sp, byte * restrict mp, int n, int w)
  212. {
  213.         while (w--)
  214.         {
  215.                 int k = n;
  216.                 int masa;
  217.                 int ma = *mp++;
  218.                 ma = FZ_EXPAND(ma);
  219.                 masa = FZ_COMBINE(sp[n-1], ma);
  220.                 masa = 255-masa;
  221.                 masa = FZ_EXPAND(masa);
  222.                 while (k--)
  223.                 {
  224.                         *dp = FZ_COMBINE2(*sp, ma, *dp, masa);
  225.                         sp++; dp++;
  226.                 }
  227.         }
  228. }
  229.  
  230. static void
  231. fz_paint_span_with_mask(byte * restrict dp, byte * restrict sp, byte * restrict mp, int n, int w)
  232. {
  233.         switch (n)
  234.         {
  235.         case 2: fz_paint_span_with_mask_2(dp, sp, mp, w); break;
  236.         case 4: fz_paint_span_with_mask_4(dp, sp, mp, w); break;
  237.         default: fz_paint_span_with_mask_N(dp, sp, mp, n, w); break;
  238.         }
  239. }
  240.  
  241. /* Blend source in constant alpha over destination */
  242.  
  243. static inline void
  244. fz_paint_span_2_with_alpha(byte * restrict dp, byte * restrict sp, int w, int alpha)
  245. {
  246.         alpha = FZ_EXPAND(alpha);
  247.         while (w--)
  248.         {
  249.                 int masa = FZ_COMBINE(sp[1], alpha);
  250.                 *dp = FZ_BLEND(*sp, *dp, masa);
  251.                 dp++; sp++;
  252.                 *dp = FZ_BLEND(*sp, *dp, masa);
  253.                 dp++; sp++;
  254.         }
  255. }
  256.  
  257. static inline void
  258. fz_paint_span_4_with_alpha(byte * restrict dp, byte * restrict sp, int w, int alpha)
  259. {
  260.         alpha = FZ_EXPAND(alpha);
  261.         while (w--)
  262.         {
  263.                 int masa = FZ_COMBINE(sp[3], alpha);
  264.                 *dp = FZ_BLEND(*sp, *dp, masa);
  265.                 sp++; dp++;
  266.                 *dp = FZ_BLEND(*sp, *dp, masa);
  267.                 sp++; dp++;
  268.                 *dp = FZ_BLEND(*sp, *dp, masa);
  269.                 sp++; dp++;
  270.                 *dp = FZ_BLEND(*sp, *dp, masa);
  271.                 sp++; dp++;
  272.         }
  273. }
  274.  
  275. static inline void
  276. fz_paint_span_N_with_alpha(byte * restrict dp, byte * restrict sp, int n, int w, int alpha)
  277. {
  278.         alpha = FZ_EXPAND(alpha);
  279.         while (w--)
  280.         {
  281.                 int masa = FZ_COMBINE(sp[n-1], alpha);
  282.                 int k = n;
  283.                 while (k--)
  284.                 {
  285.                         *dp = FZ_BLEND(*sp++, *dp, masa);
  286.                         dp++;
  287.                 }
  288.         }
  289. }
  290.  
  291. /* Blend source over destination */
  292.  
  293. static inline void
  294. fz_paint_span_1(byte * restrict dp, byte * restrict sp, int w)
  295. {
  296.         while (w--)
  297.         {
  298.                 int t = FZ_EXPAND(255 - sp[0]);
  299.                 *dp = *sp++ + FZ_COMBINE(*dp, t);
  300.                 dp ++;
  301.         }
  302. }
  303.  
  304. static inline void
  305. fz_paint_span_2(byte * restrict dp, byte * restrict sp, int w)
  306. {
  307.         while (w--)
  308.         {
  309.                 int t = FZ_EXPAND(255 - sp[1]);
  310.                 *dp = *sp++ + FZ_COMBINE(*dp, t);
  311.                 dp++;
  312.                 *dp = *sp++ + FZ_COMBINE(*dp, t);
  313.                 dp++;
  314.         }
  315. }
  316.  
  317. static inline void
  318. fz_paint_span_4(byte * restrict dp, byte * restrict sp, int w)
  319. {
  320.         while (w--)
  321.         {
  322.                 int t = FZ_EXPAND(255 - sp[3]);
  323.                 *dp = *sp++ + FZ_COMBINE(*dp, t);
  324.                 dp++;
  325.                 *dp = *sp++ + FZ_COMBINE(*dp, t);
  326.                 dp++;
  327.                 *dp = *sp++ + FZ_COMBINE(*dp, t);
  328.                 dp++;
  329.                 *dp = *sp++ + FZ_COMBINE(*dp, t);
  330.                 dp++;
  331.         }
  332. }
  333.  
  334. static inline void
  335. fz_paint_span_N(byte * restrict dp, byte * restrict sp, int n, int w)
  336. {
  337.         while (w--)
  338.         {
  339.                 int k = n;
  340.                 int t = FZ_EXPAND(255 - sp[n-1]);
  341.                 while (k--)
  342.                 {
  343.                         *dp = *sp++ + FZ_COMBINE(*dp, t);
  344.                         dp++;
  345.                 }
  346.         }
  347. }
  348.  
  349. void
  350. fz_paint_span(byte * restrict dp, byte * restrict sp, int n, int w, int alpha)
  351. {
  352.         if (alpha == 255)
  353.         {
  354.                 switch (n)
  355.                 {
  356.                 case 1: fz_paint_span_1(dp, sp, w); break;
  357.                 case 2: fz_paint_span_2(dp, sp, w); break;
  358.                 case 4: fz_paint_span_4(dp, sp, w); break;
  359.                 default: fz_paint_span_N(dp, sp, n, w); break;
  360.                 }
  361.         }
  362.         else if (alpha > 0)
  363.         {
  364.                 switch (n)
  365.                 {
  366.                 case 2: fz_paint_span_2_with_alpha(dp, sp, w, alpha); break;
  367.                 case 4: fz_paint_span_4_with_alpha(dp, sp, w, alpha); break;
  368.                 default: fz_paint_span_N_with_alpha(dp, sp, n, w, alpha); break;
  369.                 }
  370.         }
  371. }
  372.  
  373. /*
  374.  * Pixmap blending functions
  375.  */
  376.  
  377. void
  378. fz_paint_pixmap_with_rect(fz_pixmap *dst, fz_pixmap *src, int alpha, fz_bbox bbox)
  379. {
  380.         unsigned char *sp, *dp;
  381.         int x, y, w, h, n;
  382.  
  383.         assert(dst->n == src->n);
  384.  
  385.         bbox = fz_intersect_bbox(bbox, fz_bound_pixmap(dst));
  386.         bbox = fz_intersect_bbox(bbox, fz_bound_pixmap(src));
  387.  
  388.         x = bbox.x0;
  389.         y = bbox.y0;
  390.         w = bbox.x1 - bbox.x0;
  391.         h = bbox.y1 - bbox.y0;
  392.         if ((w | h) == 0)
  393.                 return;
  394.  
  395.         n = src->n;
  396.         sp = src->samples + ((y - src->y) * src->w + (x - src->x)) * src->n;
  397.         dp = dst->samples + ((y - dst->y) * dst->w + (x - dst->x)) * dst->n;
  398.  
  399.         while (h--)
  400.         {
  401.                 fz_paint_span(dp, sp, n, w, alpha);
  402.                 sp += src->w * n;
  403.                 dp += dst->w * n;
  404.         }
  405. }
  406.  
  407. void
  408. fz_paint_pixmap(fz_pixmap *dst, fz_pixmap *src, int alpha)
  409. {
  410.         unsigned char *sp, *dp;
  411.         fz_bbox bbox;
  412.         int x, y, w, h, n;
  413.  
  414.         assert(dst->n == src->n);
  415.  
  416.         bbox = fz_bound_pixmap(dst);
  417.         bbox = fz_intersect_bbox(bbox, fz_bound_pixmap(src));
  418.  
  419.         x = bbox.x0;
  420.         y = bbox.y0;
  421.         w = bbox.x1 - bbox.x0;
  422.         h = bbox.y1 - bbox.y0;
  423.         if ((w | h) == 0)
  424.                 return;
  425.  
  426.         n = src->n;
  427.         sp = src->samples + ((y - src->y) * src->w + (x - src->x)) * src->n;
  428.         dp = dst->samples + ((y - dst->y) * dst->w + (x - dst->x)) * dst->n;
  429.  
  430.         while (h--)
  431.         {
  432.                 fz_paint_span(dp, sp, n, w, alpha);
  433.                 sp += src->w * n;
  434.                 dp += dst->w * n;
  435.         }
  436. }
  437.  
  438. void
  439. fz_paint_pixmap_with_mask(fz_pixmap *dst, fz_pixmap *src, fz_pixmap *msk)
  440. {
  441.         unsigned char *sp, *dp, *mp;
  442.         fz_bbox bbox;
  443.         int x, y, w, h, n;
  444.  
  445.         assert(dst->n == src->n);
  446.         assert(msk->n == 1);
  447.  
  448.         bbox = fz_bound_pixmap(dst);
  449.         bbox = fz_intersect_bbox(bbox, fz_bound_pixmap(src));
  450.         bbox = fz_intersect_bbox(bbox, fz_bound_pixmap(msk));
  451.  
  452.         x = bbox.x0;
  453.         y = bbox.y0;
  454.         w = bbox.x1 - bbox.x0;
  455.         h = bbox.y1 - bbox.y0;
  456.         if ((w | h) == 0)
  457.                 return;
  458.  
  459.         n = src->n;
  460.         sp = src->samples + ((y - src->y) * src->w + (x - src->x)) * src->n;
  461.         mp = msk->samples + ((y - msk->y) * msk->w + (x - msk->x)) * msk->n;
  462.         dp = dst->samples + ((y - dst->y) * dst->w + (x - dst->x)) * dst->n;
  463.  
  464.         while (h--)
  465.         {
  466.                 fz_paint_span_with_mask(dp, sp, mp, n, w);
  467.                 sp += src->w * n;
  468.                 dp += dst->w * n;
  469.                 mp += msk->w;
  470.         }
  471. }
  472.