Back to index

lightning-sunbird  0.9+nobinonly
Defines | Functions | Variables
nsXFontAAScaledBitmap.cpp File Reference
#include <X11/Xatom.h>
#include "gfx-config.h"
#include "nscore.h"
#include "nsXFontAAScaledBitmap.h"
#include "nsRenderingContextGTK.h"
#include "nsX11AlphaBlend.h"
#include <gdk/gdk.h>
#include <gdk/gdkx.h>
#include "nsHashtable.h"

Go to the source code of this file.

Defines

#define IMAGE_BUFFER_SIZE   2048
#define DEBUG_DUMP(x)
#define DEBUG_SHOW_GLYPH_BOX   0
#define DEBUG_AADRAWBOX(i, x, y, w, h, r, g, b, a)
#define SRC_UP_LEFT(ps)   *(ps-padded_width-1)
#define SRC_UP(ps)   *(ps-padded_width)
#define SRC_UP_RIGHT(ps)   *(ps-padded_width+1)
#define SRC_LEFT(ps)   *(ps-1)
#define SRC(ps)   *(ps)
#define SRC_RIGHT(ps)   *(ps+1)
#define SRC_DOWN_LEFT(ps)   *(ps+padded_width-1)
#define SRC_DOWN(ps)   *(ps+padded_width)
#define SRC_DOWN_RIGHT(ps)   *(ps+padded_width+1)
#define FILL_VALUE   255

Functions

void dump_byte_table (PRUint8 *table, int width, int height)
static void scale_image (nsAntiAliasedGlyph *, nsAntiAliasedGlyph *)
static void scale_imageAntiJag (nsAntiAliasedGlyph *, nsAntiAliasedGlyph *)
static void WeightTableInitLinearCorrection (PRUint8 *, PRUint8, double)
static PRBool FreeGlyphHash (nsHashKey *aKey, void *aData, void *aClosure)

Variables

PRUint8 gAASBDarkTextMinValue = 64
double gAASBDarkTextGain = 0.6
PRUint8 gAASBLightTextMinValue = 64
double gAASBLightTextGain = 1.3

Define Documentation

#define DEBUG_AADRAWBOX (   i,
  x,
  y,
  w,
  h,
  r,
  g,
  b,
  a 
)

Definition at line 69 of file nsXFontAAScaledBitmap.cpp.

Definition at line 58 of file nsXFontAAScaledBitmap.cpp.

Definition at line 61 of file nsXFontAAScaledBitmap.cpp.

#define FILL_VALUE   255

Definition at line 52 of file nsXFontAAScaledBitmap.cpp.

#define SRC (   ps)    *(ps)
#define SRC_DOWN (   ps)    *(ps+padded_width)
#define SRC_DOWN_LEFT (   ps)    *(ps+padded_width-1)
#define SRC_DOWN_RIGHT (   ps)    *(ps+padded_width+1)
#define SRC_LEFT (   ps)    *(ps-1)
#define SRC_RIGHT (   ps)    *(ps+1)
#define SRC_UP (   ps)    *(ps-padded_width)
#define SRC_UP_LEFT (   ps)    *(ps-padded_width-1)
#define SRC_UP_RIGHT (   ps)    *(ps-padded_width+1)

Function Documentation

void dump_byte_table ( PRUint8 table,
int  width,
int  height 
)

Here is the caller graph for this function:

static PRBool FreeGlyphHash ( nsHashKey *  aKey,
void aData,
void aClosure 
) [static]

Definition at line 307 of file nsXFontAAScaledBitmap.cpp.

{
  delete (nsAntiAliasedGlyph *)aData;

  return PR_TRUE;
}

Here is the caller graph for this function:

static void scale_image ( nsAntiAliasedGlyph aSrc,
nsAntiAliasedGlyph aDst 
) [static]

Definition at line 834 of file nsXFontAAScaledBitmap.cpp.

{
  PRUint32 x, y, col;
  PRUint8 buffer[65536];
  PRUint8 *horizontally_scaled_data = buffer;
  PRUint8 *pHsd, *pDst;
  PRUint32 dst_width = aDst->GetWidth();
  PRUint32 dst_buffer_width = aDst->GetBufferWidth();
  PRUint32 dst_height = aDst->GetHeight();
  PRUint8 *dst = aDst->GetBuffer();

  if (aDst->GetBorder() != 0) {
    NS_ASSERTION(aDst->GetBorder()!=0,"border not supported");
    return;
  }

  PRUint32 ratio;

  PRUint8 *src = aSrc->GetBuffer();
  PRUint32 src_width = aSrc->GetWidth();
  NS_ASSERTION(src_width,"zero width glyph");
  if (src_width==0)
    return;

  PRUint32 src_height = aSrc->GetHeight();
  NS_ASSERTION(src_height,"zero height glyph");
  if (src_height==0)
    return;

  //
  // scale the data horizontally
  //

  // Calculate the ratio between the unscaled horizontal and
  // the scaled horizontal. Use interger multiplication 
  // using a 24.8 format fixed decimal format.
  ratio = (dst_width<<8)/src_width;

  PRUint32 hsd_len = dst_buffer_width * src_height;
  // use the stack buffer if possible
  if (hsd_len > sizeof(buffer)) {
    horizontally_scaled_data = (PRUint8*)nsMemory::Alloc(hsd_len);
    memset(horizontally_scaled_data, 0, hsd_len);
  }
  for (y=0; y<(dst_buffer_width*src_height); y++)
    horizontally_scaled_data[y] = 0;

  pHsd = horizontally_scaled_data;
  for (y=0; y<src_height; y++,pHsd+=dst_buffer_width) {
    for (x=0; x<src_width; x++) {
      // get the unscaled value
      PRUint8 src_val = src[x + (y*src_width)];
      if (!src_val)
        continue;
      // transfer the unscaled point's value to the scaled image putting
      // the correct percentage into the appropiate scaled locations
      PRUint32 area_begin = x * ratio; // starts here (24.8 format)
      PRUint32 area_end   = (x+1) * ratio; // ends here (24.8 format)
      PRUint32 end_pixel  = (area_end+255)&0xffffff00; // round to integer
      // Walk thru the scaled pixels putting in the appropiate amount.
      // col is in 24.8 format
      for (col=(area_begin&0xffffff00); col<end_pixel; col+=256) {
        // figure out how much of the unscaled pixel should go
        // in this scaled pixel
        PRUint32 this_begin = MAX(col,area_begin);
        PRUint32 this_end   = MIN((col+256), area_end);
        // add in the amount for this scaled pixel
        pHsd[col>>8] += (PRUint8)(((this_end-this_begin)*src_val)>>8);
      }
      DEBUG_DUMP((dump_byte_table(horizontally_scaled_data,
                                  dst_width, src_height)));
    }
  }

  //
  // Scale the data vertically
  //

  // Calculate the ratio between the unscaled vertical and
  // the scaled vertical. Use interger multiplication 
  // using a 24.8 format fixed decimal format.
  ratio = (dst_height<<8)/src_height;

  for (x=0; x<dst_width; x++) {
    pHsd = horizontally_scaled_data + x;
    pDst = dst + x;
    for (y=0; y<src_height; y++,pHsd+=dst_buffer_width) {
      // get the unscaled value
      PRUint8 src_val = *pHsd;
      if (src_val == 0)
        continue;
      // transfer the unscaled point's value to the scaled image putting
      // the correct percentage into the appropiate scaled locations
      PRUint32 area_begin = y * ratio; // starts here (24.8 format)
      PRUint32 area_end   = area_begin + ratio; // ends here (24.8 format)
      PRUint32 end_pixel  = (area_end+255)&0xffffff00; // round to integer
      PRUint32 c;
      PRUint32 col;
      // Walk thru the scaled pixels putting in the appropiate amount.
      // c is in 24.8 format
      for (c=(area_begin>>8)*dst_buffer_width,col=(area_begin&0xffffff00);
                col<end_pixel; c+=dst_buffer_width,col+=256) {
        // figure out how much of the unscaled pixel should go
        // in this scaled pixel
        PRUint32 this_begin = MAX(col,area_begin);
        PRUint32 this_end   = MIN((col+256), area_end);
        // add in the amount for this scaled pixel
        pDst[c] += (((this_end-this_begin)*src_val)>>8);
      }
      DEBUG_DUMP((dump_byte_table(dst, dst_width, dst_height)));
    }
  }
  if (horizontally_scaled_data != buffer)
    free(horizontally_scaled_data);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void scale_imageAntiJag ( nsAntiAliasedGlyph aSrc,
nsAntiAliasedGlyph aDst 
) [static]

Definition at line 991 of file nsXFontAAScaledBitmap.cpp.

{
  PRUint32 x, y, col;
  PRUint8 buffer[65536];
  PRUint8 *padded_src = aSrc->GetBuffer();
  PRUint8 exp_buffer[65536];
  PRUint8 *horizontally_scaled_data = buffer;
  PRUint8 *pHsd, *pDst;
  PRUint32 dst_width = aDst->GetWidth();
  PRUint32 dst_buffer_width = aDst->GetBufferWidth();
  PRUint32 dst_height = aDst->GetHeight();
  PRUint8 *dst = aDst->GetBuffer();

  if (aDst->GetBorder() != 0) {
    NS_ASSERTION(aDst->GetBorder()==0, "non zero dest border not supported");
    return;
  }
  PRUint32 expand = (((dst_width<<8)/aSrc->GetWidth())+255)>>8;

  PRUint32 src_width     = aSrc->GetWidth();
  PRUint32 src_height    = aSrc->GetHeight();
  PRUint32 border_width  = aSrc->GetBorder();
  PRUint32 padded_width  = aSrc->GetWidth()  + (2*border_width);
  PRUint32 padded_height = aSrc->GetHeight() + (2*border_width);

  //
  // Expand the data (anti-jagging comes later)
  //
  PRUint32 expanded_width  = padded_width  * expand;
  PRUint32 expanded_height = padded_height * expand;

  PRUint32 start_x = border_width * expand;
  PRUint32 start_y = border_width * expand;

  PRUint8 *expanded_data = exp_buffer;
  PRUint32 exp_len = expanded_width*expanded_height;
  if (exp_len > sizeof(exp_buffer))
    expanded_data = (PRUint8*)malloc(expanded_width*expanded_height);
  for (y=0; y<padded_height; y++) {
    for (int i=0; i<expand; i++) {
      for (x=0; x<padded_width; x++) {
        PRUint32 padded_index = x+(y*padded_width);
        PRUint32 exp_index = (x*expand) + ((i+(y*expand))*expanded_width);
        for (int j=0; j<expand; j++) {
          expanded_data[exp_index+j] = padded_src[padded_index];
        }
      }
    }
  }
  DEBUG_DUMP((dump_byte_table(expanded_data, expanded_width, expanded_height)));

// macro to access the surrounding pixels
//
// +-------+-------+-------+
// |  up   |       |  up   |
// | left  |  up   | right |
// |       |       |       |
// +-------+-------+-------+
// |       |       |       |
// | left  |  SRC  | right |
// |       |       |       |
// +-------+-------+-------+
// |       |       |       |
// | down  | down  | down  |
// | left  |       | right |
// +-------+-------+-------+
//
//
#define SRC_UP_LEFT(ps)    *(ps-padded_width-1)
#define SRC_UP(ps)         *(ps-padded_width)
#define SRC_UP_RIGHT(ps)   *(ps-padded_width+1)
#define SRC_LEFT(ps)       *(ps-1)
#define SRC(ps)            *(ps)
#define SRC_RIGHT(ps)      *(ps+1)
#define SRC_DOWN_LEFT(ps)  *(ps+padded_width-1)
#define SRC_DOWN(ps)       *(ps+padded_width)
#define SRC_DOWN_RIGHT(ps) *(ps+padded_width+1)
#define FILL_VALUE 255

  //
  // Anti-Jag by doing triangular fade-fills and fade clears.
  //
  // To do a triangular fill/clear the code needs to do a double loop: 
  //
  //    one to scan vertically
  //    one to scan horizontally the correct amount to make a triangle
  //
  // eg: 
  //
  //    for (i=0; i<jag_len; i++)
  //      for (j=0; j<jag_len-i; j++)
  //
  // The way the index is calculated determines whether the triangle is:
  // (pseudo code)
  //
  //      up-right: buf[ j - i*width]
  //       up-left: buf[-j - i*width]
  //    down-right: buf[ j + i*width]
  //     down-left: buf[-j + i*width]
  //
  // The value to fill-in/clear is related to the distance from the
  // origin of this corner. The correct value is the square root
  // of the sum of the squares. This code does a rough approximation
  // by adding the x and y offsets 
  //
  //    (i+j)
  //
  // This approximation can darken the fill fade by up to 41% but it
  // is much less CPU intensive and does not seem to affect the visual
  // quality.
  //
  // Normalize the value to the 0-1 range (24.8) by dividing by the
  // triangle's size:
  //
  // ((i+j)<<8)/jag_len
  //
  // Finally convert it to a (8 bit) value
  //
  // (((((i+j)<<8)/jag_len) * FILL_VALUE) >> 8)
  //
  // Note: this code only works for black (0) and white (255) values
  //
  DEBUG_DUMP((dump_byte_table(expanded_data, expanded_width,expanded_height)));
  PRUint8 *ps, *es;
  PRUint32 jag_len = (expand)/2; // fill/clear one half of the corner
  PRUint32 i, j;
  for (y=0; y<src_height; y++) {
    ps = padded_src + (border_width + (border_width+y)*padded_width);
    es = expanded_data
         + (border_width+((border_width+y)*expanded_width))*expand;
    for (x=0; x<src_width; x++,ps++,es+=expand) {
      //
      // Fill in the inside of corners
      //
      if (SRC(ps)==0) {
        jag_len = ((expand+1)/2);
        if ((SRC_RIGHT(ps)==255) && (SRC_DOWN(ps)==255)) {
          // triangular fade fill
          for (i=0; i<jag_len; i++)
            for (j=0; j<jag_len-i; j++)
              es[expand-1-j+((expand-1-i)*expanded_width)] =
                            255-(((((i+j)<<8)/jag_len)*FILL_VALUE)>>8);
        }
        if ((SRC_DOWN(ps)==255) && (SRC_LEFT(ps)==255)) {
          // triangular fade fill
          for (i=0; i<jag_len; i++)
            for (j=0; j<jag_len-i; j++)
              es[j+((expand-1-i)*expanded_width)] =
                            255-(((((i+j)<<8)/jag_len)*FILL_VALUE)>>8);
        }
        if ((SRC_LEFT(ps)==255) && (SRC_UP(ps)==255)) {
          // triangular fade fill
          for (i=0; i<jag_len; i++)
            for (j=0; j<jag_len-i; j++)
              es[j+(i*expanded_width)] =
                            255-(((((i+j)<<8)/jag_len)*FILL_VALUE)>>8);
        }
        if ((SRC_UP(ps)==255) && (SRC_RIGHT(ps)==255)) {
          // triangular fade fill
          for (i=0; i<jag_len; i++)
            for (j=0; j<jag_len-i; j++)
              es[expand-1-j+(i*expanded_width)] =
                            255-(((((i+j)<<8)/jag_len)*FILL_VALUE)>>8);
        }
      }
      //
      // Round off the outside of corners
      else {
        jag_len = ((expand+1)/2);
        if ((SRC_UP_LEFT(ps)==0) && (SRC_UP(ps)==0) && (SRC_LEFT(ps)==0)) {
          // triangular fade clear
          for (i=0; i<jag_len; i++)
            for (j=0; j<jag_len-i; j++)
              es[j+(i*expanded_width)] =
                            (((((i+j)<<8)/jag_len)*FILL_VALUE)>>8);
        }
        if ((SRC_UP(ps)==0) && (SRC_UP_RIGHT(ps)==0) && (SRC_RIGHT(ps)==0)) {
          // triangular fade clear
          for (i=0; i<jag_len; i++)
            for (j=0; j<jag_len-i; j++)
              es[expand-1-j+(i*expanded_width)] =
                            (((((i+j)<<8)/jag_len)*FILL_VALUE)>>8);
        }
        if ((SRC_LEFT(ps)==0) && (SRC_DOWN_LEFT(ps)==0) && (SRC_DOWN(ps)==0)) {
          // triangular fade clear
          for (i=0; i<jag_len; i++)
            for (j=0; j<jag_len-i; j++)
              es[j+((expand-1-i)*expanded_width)] =
                            (((((i+j)<<8)/jag_len)*FILL_VALUE)>>8);
        }
        if ((SRC_RIGHT(ps)==0) && (SRC_DOWN_RIGHT(ps)==0) && (SRC_DOWN(ps)==0)){
          // triangular fade clear
          for (i=0; i<jag_len; i++)
            for (j=0; j<jag_len-i; j++)
              es[(expand-1-j)+((expand-1-i)*expanded_width)] =
                            (((((i+j)<<8)/jag_len)*FILL_VALUE)>>8);
        }
      }
    }
  }
  DEBUG_DUMP((dump_byte_table(expanded_data, expanded_width,expanded_height)));

  //
  // scale the data horizontally
  //
  // note: size is +dst_buffer_width because the loop can go one pixel
  // (horizontal or vertical) past array (with a near 0 width area)
  PRUint32 ratio = ((dst_width<<8)/expand)/src_width;

  PRUint32 hsd_len = (dst_buffer_width+1) * expanded_height;
  if (hsd_len > sizeof(buffer)) {
    horizontally_scaled_data = (PRUint8*)nsMemory::Alloc(hsd_len);
    memset(horizontally_scaled_data, 0, hsd_len);
  }
  for (i=0; i<hsd_len; i++)
    horizontally_scaled_data[i] = 0;

  PRUint32 len_x   = src_width * expand;
  pHsd = horizontally_scaled_data;
  for (y=0; y<expanded_height; y++,pHsd+=dst_buffer_width) {
    for (x=0; x<len_x; x++) {
      PRUint32 exp_index = start_x + x + (y*expanded_width);
      PRUint8 src_val = expanded_data[exp_index];
      if (!src_val)
        continue;
      PRUint32 area_begin = x * ratio;
      PRUint32 area_end   = (x+1) * ratio;
      PRUint32 end_pixel   = (area_end+255)&0xffffff00;
      for (col=(area_begin&0xffffff00); col<end_pixel; col+=256) {
        PRUint32 this_begin = MAX(col,area_begin);
        PRUint32 this_end   = MIN((col+256), area_end);
        pHsd[col>>8] += (PRUint8)(((this_end-this_begin)*src_val)>>8);
        if ((&pHsd[col>>8]-horizontally_scaled_data) > (int)hsd_len) {
          NS_ASSERTION(0, "buffer too small");
          return;
        }
      }
    }

    DEBUG_DUMP((dump_byte_table(horizontally_scaled_data,
                dst_width, expanded_height)));
  }

  //
  // scale the data vertically
  //
  ratio = ((dst_height<<8)/expand)/src_height;
  PRUint32 len_y   = src_height * expand;
  for (x=0; x<dst_width; x++) {
    pHsd = horizontally_scaled_data + x + (start_y*dst_buffer_width);
    pDst = dst + x;
    for (y=0; y<len_y; y++,pHsd+=dst_buffer_width) {
      PRUint8 src_val = *pHsd;
      if (src_val == 0)
        continue;
      PRUint32 area_begin = y * ratio;
      PRUint32 area_end   = area_begin + ratio;
      PRUint32 end_pixel   = (area_end+255)&0xffffff00;
      PRUint32 c;
      PRUint32 col;
      for (c=(area_begin>>8)*dst_buffer_width,col=(area_begin&0xffffff00);
                  col<end_pixel; c+=dst_buffer_width,col+=256) {
        PRUint32 this_begin = MAX(col,area_begin);
        PRUint32 this_end   = MIN((col+256), area_end);
        PRUint32 val = (((this_end-this_begin)*src_val)>>8);
        pDst[c] += val;
      }
    }
    DEBUG_DUMP((dump_byte_table(dst, dst_width, dst_height)));
  }
  if (expanded_data != exp_buffer)
    free(expanded_data);
  if (horizontally_scaled_data != buffer)
    free(horizontally_scaled_data);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void WeightTableInitLinearCorrection ( PRUint8 aTable,
PRUint8  aMinValue,
double  aGain 
) [static]

Definition at line 1339 of file nsXFontAAScaledBitmap.cpp.

{
  // setup the wieghting table
  for (int i=0; i<256; i++) {
    int val = i;
    if (i>=aMinValue)
      val += (int)rint((double)(i-aMinValue)*aGain);
    val = MAX(0, val);
    val = MIN(val, 255);
    aTable[i] = (PRUint8)val;
  }
}

Here is the caller graph for this function:


Variable Documentation

double gAASBDarkTextGain = 0.6

Definition at line 117 of file nsXFontAAScaledBitmap.cpp.

Definition at line 116 of file nsXFontAAScaledBitmap.cpp.

double gAASBLightTextGain = 1.3

Definition at line 119 of file nsXFontAAScaledBitmap.cpp.

Definition at line 118 of file nsXFontAAScaledBitmap.cpp.