]> git.imager.perl.org - imager.git/blobdiff - W32/win32.c
rename font.c to fontft1.c, since it only does FT1 now
[imager.git] / W32 / win32.c
index b466d99156e759eff347e66452b68553891ee49e..6da43946c056f098da3c0d4045cbaa777cfee022 100644 (file)
@@ -11,7 +11,7 @@ win32.c - implements some win32 specific code, specifically Win32 font support.
 
 =head1 SYNOPSIS
 
-   int bbox[6];
+   i_img_dim bbox[6];
    if (i_wf_bbox(facename, size, text, text_len, bbox)) {
      // we have the bbox
    }
@@ -31,9 +31,10 @@ An Imager interface to font output using the Win32 GDI.
 
 static void set_logfont(const char *face, int size, LOGFONT *lf);
 
-static LPVOID render_text(const char *face, int size, const char *text, int length, int aa,
-                          HBITMAP *pbm, SIZE *psz, TEXTMETRIC *tm, int *bbox, int utf8);
+static unsigned char *render_text(const char *face, int size, const char *text, size_t length, int aa,
+                                 SIZE *psz, TEXTMETRIC *tm, size_t *bytes_per_line, i_img_dim *bbox, int utf8);
 static LPWSTR utf8_to_wide_string(char const *text, int text_len, int *wide_chars);
+static LPWSTR latin1_to_wide_string(char const *text, int text_len, int *wide_chars);
 
 /*
 =item i_wf_bbox(face, size, text, length, bbox, utf8)
@@ -43,8 +44,8 @@ Calculate a bounding box for the text.
 =cut
 */
 
-int i_wf_bbox(const char *face, int size, const char *text, int length, int *bbox,
-             int utf8) {
+int i_wf_bbox(const char *face, i_img_dim size, const char *text, size_t length,
+             i_img_dim *bbox, int utf8) {
   LOGFONT lf;
   HFONT font, oldFont;
   HDC dc;
@@ -59,6 +60,8 @@ int i_wf_bbox(const char *face, int size, const char *text, int length, int *bbo
   int got_first_ch = 0;
   unsigned long first_ch, last_ch;
 
+  i_clear_error();
+
   mm_log((1, "i_wf_bbox(face %s, size %d, text %p, length %d, bbox %p, utf8 %d)\n", face, size, text, length, bbox, utf8));
 
   set_logfont(face, size, &lf);
@@ -172,7 +175,11 @@ int i_wf_bbox(const char *face, int size, const char *text, int length, int *bbo
   ReleaseDC(NULL, dc);
   DeleteObject(font);
 
-  mm_log((1, " bbox=> negw=%d glob_desc=%d pos_wid=%d glob_asc=%d desc=%d asc=%d adv_width=%d rightb=%d\n", bbox[0], bbox[1], bbox[2], bbox[3], bbox[4], bbox[5], bbox[6], bbox[7]));
+  mm_log((1, " bbox=> negw=%" i_DF " glob_desc=%" i_DF " pos_wid=%" i_DF
+         " glob_asc=%" i_DF " desc=%" i_DF " asc=%" i_DF " adv_width=%" i_DF 
+         " rightb=%" i_DF "\n", i_DFc(bbox[0]), i_DFc(bbox[1]), i_DFc(bbox[2]),
+         i_DFc(bbox[3]), i_DFc(bbox[4]), i_DFc(bbox[5]), i_DFc(bbox[6]),
+         i_DFc(bbox[7])));
 
   return BBOX_RIGHT_BEARING + 1;
 }
@@ -186,30 +193,31 @@ Draws the text in the given color.
 */
 
 int
-i_wf_text(const char *face, i_img *im, int tx, int ty, const i_color *cl, int size, 
-         const char *text, int len, int align, int aa, int utf8) {
+i_wf_text(const char *face, i_img *im, i_img_dim tx, i_img_dim ty, const i_color *cl, i_img_dim size, 
+         const char *text, size_t len, int align, int aa, int utf8) {
   unsigned char *bits;
-  HBITMAP bm;
   SIZE sz;
-  int line_width;
-  int x, y;
+  size_t line_width;
+  i_img_dim x, y;
   int ch;
   TEXTMETRIC tm;
   int top;
-  int bbox[BOUNDING_BOX_COUNT];
+  i_img_dim bbox[BOUNDING_BOX_COUNT];
+  i_render *r;
+  unsigned char *outp;
+
+  i_clear_error();
 
-  mm_log((1, "i_wf_text(face %s, im %p, tx %d, ty %d, cl %p, size %d, text %p, length %d, align %d, aa %d,  utf8 %d)\n", face, im, tx, ty, cl, size, text, len, align, aa, aa, utf8));
+  mm_log((1, "i_wf_text(face %s, im %p, tx %" i_DF ", ty %" i_DF ", cl %p, size %" i_DF ", text %p, length %lu, align %d, aa %d,  utf8 %d)\n", face, im, i_DFcp(tx, ty), cl, i_DFc(size), text, (unsigned long)len, align, aa, aa, utf8));
 
   if (!i_wf_bbox(face, size, text, len, bbox, utf8))
     return 0;
 
-  bits = render_text(face, size, text, len, aa, &bm, &sz, &tm, bbox, utf8);
+  bits = render_text(face, size, text, len, aa, &sz, &tm, &line_width, bbox, utf8);
   if (!bits)
     return 0;
-  
+
   tx += bbox[BBOX_NEG_WIDTH];
-  line_width = sz.cx * 3;
-  line_width = (line_width + 3) / 4 * 4;
   top = ty;
   if (align) {
     top -= tm.tmAscent;
@@ -218,20 +226,14 @@ i_wf_text(const char *face, i_img *im, int tx, int ty, const i_color *cl, int si
     top -= tm.tmAscent - bbox[BBOX_ASCENT];
   }
 
+  r = i_render_new(im, sz.cx);
+  outp = bits;
   for (y = 0; y < sz.cy; ++y) {
-    for (x = 0; x < sz.cx; ++x) {
-      i_color pel;
-      int scale = bits[3 * x];
-      i_gpix(im, tx+x, top+sz.cy-y-1, &pel);
-      for (ch = 0; ch < im->channels; ++ch) {
-       pel.channel[ch] = 
-         ((255-scale) * pel.channel[ch] + scale*cl->channel[ch]) / 255;
-      }
-      i_ppix(im, tx+x, top+sz.cy-y-1, &pel);
-    }
-    bits += line_width;
+    i_render_color(r, tx, top + sz.cy - y - 1, sz.cx, outp, cl);
+    outp += line_width;
   }
-  DeleteObject(bm);
+  i_render_delete(r);
+  myfree(bits);
 
   return 1;
 }
@@ -245,28 +247,28 @@ Draws the text in the given channel.
 */
 
 int
-i_wf_cp(const char *face, i_img *im, int tx, int ty, int channel, int size, 
-         const char *text, int len, int align, int aa, int utf8) {
+i_wf_cp(const char *face, i_img *im, i_img_dim tx, i_img_dim ty, int channel, i_img_dim size, 
+         const char *text, size_t len, int align, int aa, int utf8) {
   unsigned char *bits;
-  HBITMAP bm;
   SIZE sz;
-  int line_width;
-  int x, y;
+  size_t line_width;
+  i_img_dim x, y;
   TEXTMETRIC tm;
-  int top;
-  int bbox[BOUNDING_BOX_COUNT];
+  i_img_dim top;
+  i_img_dim bbox[BOUNDING_BOX_COUNT];
+  unsigned char *outp;
 
-  mm_log((1, "i_wf_cp(face %s, im %p, tx %d, ty %d, channel %d, size %d, text %p, length %d, align %d, aa %d,  utf8 %d)\n", face, im, tx, ty, channel, size, text, len, align, aa, aa, utf8));
+  i_clear_error();
+
+  mm_log((1, "i_wf_cp(face %s, im %p, tx %" i_DF ", ty %" i_DF ", channel %d, size %" i_DF ", text %p, length %lu, align %d, aa %d,  utf8 %d)\n", face, im, i_DFcp(tx, ty), channel, i_DFc(size), text, (unsigned long)len, align, aa, aa, utf8));
 
   if (!i_wf_bbox(face, size, text, len, bbox, utf8))
     return 0;
 
-  bits = render_text(face, size, text, len, aa, &bm, &sz, &tm, bbox, utf8);
+  bits = render_text(face, size, text, len, aa, &sz, &tm, &line_width, bbox, utf8);
   if (!bits)
     return 0;
   
-  line_width = sz.cx * 3;
-  line_width = (line_width + 3) / 4 * 4;
   top = ty;
   if (align) {
     top -= tm.tmAscent;
@@ -275,17 +277,18 @@ i_wf_cp(const char *face, i_img *im, int tx, int ty, int channel, int size,
     top -= tm.tmAscent - bbox[BBOX_ASCENT];
   }
 
+  outp = bits;
   for (y = 0; y < sz.cy; ++y) {
     for (x = 0; x < sz.cx; ++x) {
       i_color pel;
-      int scale = bits[3 * x];
+      int scale = outp[x];
       i_gpix(im, tx+x, top+sz.cy-y-1, &pel);
       pel.channel[channel] = scale;
       i_ppix(im, tx+x, top+sz.cy-y-1, &pel);
     }
-    bits += line_width;
+    outp += line_width;
   }
-  DeleteObject(bm);
+  myfree(bits);
 
   return 1;
 }
@@ -312,25 +315,33 @@ int
 i_wf_addfont(char const *filename) {
   i_clear_error();
 
+  mm_log((1, "i_wf_addfont(%s)\n", filename));
   if (!gdi_dll) {
     gdi_dll = GetModuleHandle("GDI32");
     if (gdi_dll) {
       AddFontResourceExAp = (AddFontResourceExA_t)GetProcAddress(gdi_dll, "AddFontResourceExA");
       RemoveFontResourceExAp = (RemoveFontResourceExA_t)GetProcAddress(gdi_dll, "RemoveFontResourceExA");
+      mm_log((1, "i_wf_addfont: AddFontResourceExA %p RemoveFontResourceExA %p\n",
+             AddFontResourceExAp, RemoveFontResourceExAp));
     }
   }
 
-  if (AddFontResourceExAp && RemoveFontResourceExAp
-      && AddFontResourceExAp(filename, FR_PRIVATE, 0)) {
-    return 1;
-  }
-  else if (AddFontResource(filename)) {
-    return 1;
+  if (AddFontResourceExAp && RemoveFontResourceExAp) {
+    mm_log((1, "i_wf_addfont: adding via AddFontResourceEx()\n"));
+    if (AddFontResourceExAp(filename, FR_PRIVATE, 0)) {
+      return 1;
+    }
   }
   else {
-    i_push_errorf(0, "Could not add resource: %ld", GetLastError());
-    return 0;
+    mm_log((1, "i_wf_addfont: adding via AddFontResource()\n"));
+    if (AddFontResource(filename)) {
+      return 1;
+    }
   }
+
+  mm_log((1, "i_wf_addfont failed: %ld\n", GetLastError()));
+  i_push_errorf(0, "Could not add resource: %ld", GetLastError());
+  return 0;
 }
 
 /*
@@ -344,17 +355,22 @@ int
 i_wf_delfont(char const *filename) {
   i_clear_error();
 
-  if (AddFontResourceExAp && RemoveFontResourceExAp
-      && RemoveFontResourceExAp(filename, FR_PRIVATE, 0)) {
-    return 1;
-  }
-  else if (RemoveFontResource(filename)) {
-    return 1;
+  mm_log((1, "i_wf_delfont(%s)\n", filename));
+
+  if (AddFontResourceExAp && RemoveFontResourceExAp) {
+    mm_log((1, "i_wf_delfont: removing via RemoveFontResourceEx()\n"));
+    if (RemoveFontResourceExAp(filename, FR_PRIVATE, 0))
+      return 1;
   }
   else {
-    i_push_errorf(0, "Could not remove resource: %ld", GetLastError());
-    return 0;
+    mm_log((1, "i_wf_delfont: adding via RemoveFontResourceEx()\n"));
+    if (RemoveFontResource(filename))
+      return 1;
   }
+
+  mm_log((1, "i_wf_delfont failed: %ld\n", GetLastError()));
+  i_push_errorf(0, "Could not remove resource: %ld", GetLastError());
+  return 0;
 }
 
 /*
@@ -393,8 +409,9 @@ native greyscale bitmaps.
 
 =cut
 */
-static LPVOID render_text(const char *face, int size, const char *text, int length, int aa,
-                  HBITMAP *pbm, SIZE *psz, TEXTMETRIC *tm, int *bbox, int utf8) {
+static unsigned char *
+render_text(const char *face, int size, const char *text, size_t length, int aa,
+           SIZE *psz, TEXTMETRIC *tm, size_t *bytes_per_line, i_img_dim *bbox, int utf8) {
   BITMAPINFO bmi;
   BITMAPINFOHEADER *bmih = &bmi.bmiHeader;
   HDC dc, bmpDc;
@@ -405,6 +422,7 @@ static LPVOID render_text(const char *face, int size, const char *text, int leng
   LPVOID bits;
   int wide_count;
   LPWSTR wide_text;
+  unsigned char *result;
 
   dc = GetDC(NULL);
   set_logfont(face, size, &lf);
@@ -420,7 +438,7 @@ static LPVOID render_text(const char *face, int size, const char *text, int leng
     wide_text = utf8_to_wide_string(text, length, &wide_count);
   }
   else {
-    wide_text = NULL;
+    wide_text = latin1_to_wide_string(text, length, &wide_count);
   }
 
   bmpDc = CreateCompatibleDC(dc);
@@ -452,12 +470,7 @@ static LPVOID render_text(const char *face, int size, const char *text, int leng
        oldBm = SelectObject(bmpDc, bm);
        SetTextColor(bmpDc, RGB(255, 255, 255));
        SetBkColor(bmpDc, RGB(0, 0, 0));
-       if (utf8) {
-         TextOutW(bmpDc, -bbox[BBOX_NEG_WIDTH], 0, wide_text, wide_count);
-       }
-       else {
-         TextOut(bmpDc, -bbox[BBOX_NEG_WIDTH], 0, text, length);
-       }
+       TextOutW(bmpDc, -bbox[BBOX_NEG_WIDTH], 0, wide_text, wide_count);
        SelectObject(bmpDc, oldBm);
       }
       else {
@@ -467,16 +480,14 @@ static LPVOID render_text(const char *face, int size, const char *text, int leng
        DeleteObject(font);
        DeleteDC(bmpDc);
        ReleaseDC(NULL, dc);
-       if (wide_text)
-         myfree(wide_text);
+       myfree(wide_text);
        return NULL;
       }
       SelectObject(bmpDc, oldFont);
       DeleteObject(font);
     }
     else {
-      if (wide_text)
-       myfree(wide_text);
+      myfree(wide_text);
       i_push_errorf(0, "Could not create logical font: %ld",
                    GetLastError());
       DeleteDC(bmpDc);
@@ -486,22 +497,41 @@ static LPVOID render_text(const char *face, int size, const char *text, int leng
     DeleteDC(bmpDc);
   }
   else {
-    if (wide_text)
-      myfree(wide_text);
+    myfree(wide_text);
     i_push_errorf(0, "Could not create rendering DC: %ld", GetLastError());
     ReleaseDC(NULL, dc);
     return NULL;
   }
 
-  if (wide_text)
-    myfree(wide_text);
+  myfree(wide_text);
 
   ReleaseDC(NULL, dc);
 
-  *pbm = bm;
   *psz = sz;
 
-  return bits;
+  /* convert into a map we can just pass to i_render_color() */
+  {
+    i_img_dim x, y;
+    unsigned char *outp, *ucbits;
+    size_t bits_line_width;
+
+    *bytes_per_line = sz.cx;
+    result = mymalloc(sz.cx * sz.cy);
+    outp = result;
+    ucbits = bits;
+    bits_line_width = sz.cx * 3;
+    bits_line_width = (bits_line_width + 3) / 4 * 4;
+
+    for (y = 0; y < sz.cy; ++y) {
+      for (x = 0; x < sz.cx; ++x) {
+       *outp++ = ucbits[3 * x];
+      }
+      ucbits += bits_line_width;
+    }
+  }
+  DeleteObject(bm);
+
+  return result;
 }
 
 /*
@@ -533,6 +563,19 @@ utf8_to_wide_string(char const *text, int text_len, int *wide_chars) {
   return result;
 }
 
+static LPWSTR
+latin1_to_wide_string(char const *text, int text_len, int *wide_chars) {
+  LPWSTR result = mymalloc(sizeof(WCHAR) * (text_len + 1));
+  size_t i;
+
+  for (i = 0; i < text_len; ++i) {
+    result[i] = (unsigned char)text[i];
+  }
+  result[i] = 0;
+  *wide_chars = text_len;
+
+  return result;
+}
 
 /*
 =back