Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | Download | RSS feed

  1. /*
  2.  * Copyright 2008 Adam Blokus <adamblokus@gmail.com>
  3.  * Copyright 2009 John Tytgat <joty@netsurf-browser.org>
  4.  *
  5.  * This file is part of NetSurf, http://www.netsurf-browser.org/
  6.  *
  7.  * NetSurf is free software; you can redistribute it and/or modify
  8.  * it under the terms of the GNU General Public License as published by
  9.  * the Free Software Foundation; version 2 of the License.
  10.  *
  11.  * NetSurf is distributed in the hope that it will be useful,
  12.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.  * GNU General Public License for more details.
  15.  *
  16.  * You should have received a copy of the GNU General Public License
  17.  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  18.  */
  19.  
  20.  /** \file
  21.   * Font handling in Haru pdf documents (implementation).
  22.   *
  23.   * The functions were written to implement the same interface as the Pango ones
  24.   * so that the usage of the latter wouldn't have to be modified.
  25.   */
  26.  
  27. #include "utils/config.h"
  28. #ifdef WITH_PDF_EXPORT
  29.  
  30. /*#define FONT_HARU_DEBUG */
  31.  
  32. #include <assert.h>
  33. #include <float.h>
  34. #include <math.h>
  35. #include <string.h>
  36.  
  37. #include <hpdf.h>
  38.  
  39. #include "css/css.h"
  40. #include "css/utils.h"
  41.  
  42. #include "desktop/options.h"
  43. #include "desktop/save_pdf/font_haru.h"
  44. #include "render/font.h"
  45. #include "utils/log.h"
  46.  
  47.  
  48. static bool haru_nsfont_init(HPDF_Doc *pdf, HPDF_Page *page,
  49.                 const char *string, char **string_nt, int length);
  50.  
  51. static bool haru_nsfont_width(const plot_font_style_t *fstyle,
  52.                 const char *string, size_t length,
  53.                 int *width);
  54.  
  55. static bool haru_nsfont_position_in_string(const plot_font_style_t *fstyle,
  56.                 const char *string, size_t length,
  57.                 int x, size_t *char_offset, int *actual_x);
  58.  
  59. static bool haru_nsfont_split(const plot_font_style_t *fstyle,
  60.                 const char *string, size_t length,
  61.                 int x, size_t *char_offset, int *actual_x);
  62.                
  63. static float pdf_text_scale = DEFAULT_EXPORT_SCALE;
  64.  
  65. const struct font_functions haru_nsfont = {
  66.         haru_nsfont_width,
  67.         haru_nsfont_position_in_string,
  68.         haru_nsfont_split
  69. };
  70.  
  71. /**
  72.  * Haru error handler
  73.  * for debugging purposes - it immediately exits the program on the first error,
  74.  * as it would otherwise flood the user with all resulting complications,
  75.  * covering the most important error source.
  76.  */
  77. static void error_handler(HPDF_STATUS error_no, HPDF_STATUS detail_no,
  78.                 void *user_data)
  79. {
  80.         LOG(("ERROR: in font_haru \n\terror_no=%x\n\tdetail_no=%d\n",
  81.                         (HPDF_UINT)error_no, (HPDF_UINT)detail_no));
  82. #ifdef FONT_HARU_DEBUG 
  83.         exit(1);
  84. #endif 
  85. }
  86.  
  87. static bool haru_nsfont_init(HPDF_Doc *pdf, HPDF_Page *page,
  88.                 const char *string, char **string_nt, int length)
  89. {
  90.        
  91.         *pdf = HPDF_New(error_handler, NULL);
  92.        
  93.         if (*pdf == NULL)
  94.                 return false;
  95.  
  96.         *page = HPDF_AddPage(*pdf);
  97.        
  98.         if (*page == NULL) {
  99.                 HPDF_Free(*pdf);
  100.                 return false;  
  101.         }
  102.        
  103.         *string_nt = malloc((length + 1) * sizeof(char));
  104.         if (*string_nt == NULL) {
  105.                 HPDF_Free(*pdf);
  106.                 return false;
  107.         }
  108.        
  109.         memcpy(*string_nt, string, length);
  110.         (*string_nt)[length] = '\0';   
  111.         return true;
  112. }
  113.  
  114. /**
  115.  * Measure the width of a string.
  116.  *
  117.  * \param  fstyle  style for this text
  118.  * \param  string  string to measure (no UTF-8 currently)
  119.  * \param  length  length of string
  120.  * \param  width   updated to width of string[0..length]
  121.  * \return  true on success, false on error and error reported
  122.  */
  123. bool haru_nsfont_width(const plot_font_style_t *fstyle,
  124.                 const char *string, size_t length,
  125.                 int *width)
  126. {
  127.         HPDF_Doc pdf;
  128.         HPDF_Page page;
  129.         char *string_nt;
  130.         HPDF_REAL width_real;
  131.  
  132.         *width = 0;
  133.  
  134.         if (length == 0)
  135.                 return true;
  136.  
  137.         if (!haru_nsfont_init(&pdf, &page, string, &string_nt, length))
  138.                 return false;
  139.  
  140.         if (!haru_nsfont_apply_style(fstyle, pdf, page, NULL, NULL)) {
  141.                 free(string_nt);
  142.                 HPDF_Free(pdf);
  143.                 return false;
  144.         }
  145.  
  146.         width_real = HPDF_Page_TextWidth(page, string_nt);
  147.         *width = width_real;
  148.  
  149. #ifdef FONT_HARU_DEBUG         
  150.         LOG(("Measuring string: %s ; Calculated width: %f %i",string_nt, width_real, *width));
  151. #endif
  152.         free(string_nt);
  153.         HPDF_Free(pdf);
  154.  
  155.         return true;
  156. }
  157.  
  158.  
  159. /**
  160.  * Find the position in a string where an x coordinate falls.
  161.  *
  162.  * \param  fstyle       style for this text
  163.  * \param  string       string to measure (no UTF-8 currently)
  164.  * \param  length       length of string
  165.  * \param  x            x coordinate to search for
  166.  * \param  char_offset  updated to offset in string of actual_x, [0..length]
  167.  * \param  actual_x     updated to x coordinate of character closest to x
  168.  * \return  true on success, false on error and error reported
  169.  */
  170.  
  171. bool haru_nsfont_position_in_string(const plot_font_style_t *fstyle,
  172.                 const char *string, size_t length,
  173.                 int x, size_t *char_offset, int *actual_x)
  174. {
  175.         HPDF_Doc pdf;
  176.         HPDF_Page page;
  177.         char *string_nt;
  178.         HPDF_UINT offset;
  179.         HPDF_REAL real_width;
  180.        
  181.         if (!haru_nsfont_init(&pdf, &page, string, &string_nt, length))
  182.                 return false;
  183.        
  184.         if (HPDF_Page_SetWidth(page, x) != HPDF_OK
  185.                         || !haru_nsfont_apply_style(fstyle, pdf, page, NULL, NULL)) {
  186.                 free(string_nt);
  187.                 HPDF_Free(pdf);
  188.                 return false;
  189.         }
  190.  
  191.        
  192.         offset = HPDF_Page_MeasureText(page, string_nt, x,
  193.                         HPDF_FALSE, &real_width);
  194.        
  195.  
  196.         if (real_width < x)
  197.                 *char_offset = offset;
  198.         else {
  199.                 assert(fabs(real_width - x) < FLT_EPSILON);
  200.                 assert(offset > 0);
  201.                 *char_offset = offset - 1;
  202.         }
  203.        
  204.         /*TODO: this is only the right edge of the character*/
  205.         *actual_x = real_width;
  206.        
  207. #ifdef FONT_HARU_DEBUG 
  208.         LOG(("Position in string: %s at x: %i; Calculated position: %i",
  209.                         string_nt, x, *char_offset));  
  210. #endif 
  211.         free(string_nt);
  212.         HPDF_Free(pdf);
  213.        
  214.         return true;
  215. }
  216.  
  217. /**
  218.  * Find where to split a string to make it fit a width.
  219.  *
  220.  * \param  fstyle       style for this text
  221.  * \param  string       string to measure (no UTF-8 currently)
  222.  * \param  length       length of string
  223.  * \param  x            width available
  224.  * \param  char_offset  updated to offset in string of actual_x, [0..length]
  225.  * \param  actual_x     updated to x coordinate of character closest to x
  226.  * \return  true on success, false on error and error reported
  227.  */
  228.  
  229. bool haru_nsfont_split(const plot_font_style_t *fstyle,
  230.                 const char *string, size_t length,
  231.                 int x, size_t *char_offset, int *actual_x)
  232. {
  233.         HPDF_Doc pdf;
  234.         HPDF_Page page;
  235.         char *string_nt;
  236.         HPDF_REAL real_width;
  237.         HPDF_UINT offset;
  238.        
  239.        
  240.         if (!haru_nsfont_init(&pdf, &page, string, &string_nt, length))
  241.                 return false;
  242.        
  243.         if (HPDF_Page_SetWidth(page, x) != HPDF_OK
  244.                     || !haru_nsfont_apply_style(fstyle, pdf, page, NULL, NULL)) {
  245.                 free(string_nt);
  246.                 HPDF_Free(pdf);
  247.                 return false;
  248.         }
  249.        
  250.         offset = HPDF_Page_MeasureText(page, string_nt, x,
  251.                         HPDF_TRUE, &real_width);
  252.        
  253. #ifdef FONT_HARU_DEBUG 
  254.         LOG(("Splitting string: %s for width: %i ; Calculated position: %i Calculated real_width: %f",
  255.         string_nt, x, *char_offset, real_width));      
  256. #endif 
  257.         *char_offset = offset - 1;
  258.        
  259.         /*TODO: this is only the right edge of the character*/
  260.         *actual_x = real_width;
  261.        
  262.         free(string_nt);
  263.         HPDF_Free(pdf);
  264.        
  265.         return true;   
  266. }
  267.  
  268. /**
  269.  * Apply font style to a Haru HPDF_Page
  270.  *
  271.  * \param  fstyle       plot style for this page
  272.  * \param  doc          document owning the page
  273.  * \param  page         the page to apply the style to
  274.  * \param  font         if this is non NULL it is updated to the font based
  275.  *                      on given style
  276.  * \param  font_size    if this is non NULL it is updated to the font size
  277.  *                      based on given style
  278.  * \return true on success, false on error and error reported
  279.  *
  280.  * When both font and font_size are NULL, the HPDF_Page is updated for given
  281.  * style, otherwise it is left to the called to do this.
  282.  */
  283. bool haru_nsfont_apply_style(const plot_font_style_t *fstyle,
  284.                 HPDF_Doc doc, HPDF_Page page,
  285.                 HPDF_Font *font, HPDF_REAL *font_size)
  286. {
  287.         HPDF_Font pdf_font;
  288.         HPDF_REAL size;
  289.         char font_name[50];
  290.         bool roman = false;
  291.         bool bold = false;
  292.         bool styled = false;
  293.  
  294.         /*TODO: style handling, we are mapping the
  295.                 styles on the basic 14 fonts only
  296.         */
  297.         switch (fstyle->family) {
  298.         case PLOT_FONT_FAMILY_SERIF:
  299.                 strcpy(font_name, "Times");
  300.                 roman = true;
  301.                 break;
  302.         case PLOT_FONT_FAMILY_MONOSPACE:
  303.                 strcpy(font_name, "Courier");
  304.                 break;
  305.         case PLOT_FONT_FAMILY_SANS_SERIF:
  306.                 strcpy(font_name, "Helvetica");
  307.                 break;
  308.         case PLOT_FONT_FAMILY_CURSIVE:                 
  309.         case PLOT_FONT_FAMILY_FANTASY:         
  310.         default:
  311.                 strcpy(font_name, "Times");
  312.                 roman=true;
  313.                 break;
  314.         }
  315.        
  316.         if (fstyle->weight == 700) {
  317.                 strcat(font_name, "-Bold");
  318.                 bold = true;
  319.         }
  320.  
  321.         if ((fstyle->flags & FONTF_ITALIC) || (fstyle->flags & FONTF_OBLIQUE)) {
  322.                 if (!bold)
  323.                         strcat(font_name,"-");
  324.                 if (roman)
  325.                         strcat(font_name,"Italic");
  326.                 else
  327.                         strcat(font_name,"Oblique");
  328.                        
  329.                 styled = true;
  330.         }
  331.        
  332.         if (roman && !styled && !bold)
  333.                 strcat(font_name, "-Roman");
  334.  
  335. #ifdef FONT_HARU_DEBUG         
  336.         LOG(("Setting font: %s", font_name));
  337. #endif         
  338.  
  339.         size = fstyle->size;
  340.  
  341.         if (font != NULL)
  342.                 size *= pdf_text_scale;
  343.  
  344.         if (size <= 0)
  345.                 return true;
  346.  
  347.         size /= FONT_SIZE_SCALE;
  348.  
  349.         if (size > HPDF_MAX_FONTSIZE)
  350.                 size = HPDF_MAX_FONTSIZE;
  351.  
  352.         if (font_size)
  353.                 *font_size = size;
  354.  
  355.         pdf_font = HPDF_GetFont(doc, font_name, "StandardEncoding");
  356.         if (pdf_font == NULL)
  357.                 return false;
  358.         if (font != NULL)
  359.                 *font = pdf_font;
  360.  
  361.         if (font == NULL || font_size == NULL)
  362.                 HPDF_Page_SetFontAndSize(page, pdf_font, size);
  363.        
  364.         return true;
  365. }
  366.  
  367. /**
  368.  * Sync the text scale with the scale for the whole content
  369.  */
  370. void haru_nsfont_set_scale(float s)
  371. {
  372.         pdf_text_scale = s;
  373. }
  374.  
  375. #endif /* WITH_PDF_EXPORT */
  376.  
  377.