Index: render.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/render/render.module,v
retrieving revision 1.1.2.6
diff -u -p -r1.1.2.6 render.module
--- render.module	12 Sep 2008 20:42:47 -0000	1.1.2.6
+++ render.module	13 Sep 2008 12:28:17 -0000
@@ -114,7 +114,7 @@ function render_plugins() {
   }
   
   $dir = drupal_get_path('module', 'render') .'/plugins';
-  $listing = file_scan_directory($dir, '.+\.inc', array('.', '..', 'CVS', '.svn'), 0, FALSE, 'name');
+  $listing = file_scan_directory($dir, '.+\.inc$', array('.', '..', 'CVS', '.svn'), 0, FALSE, 'name');
   foreach ($listing as $plugin) {
     include_once($plugin->filename);
     $function = $plugin->name .'_render_info';
Index: jitr/heading.php
===================================================================
RCS file: jitr/heading.php
diff -N jitr/heading.php
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ jitr/heading.php	13 Sep 2008 12:19:37 -0000
@@ -0,0 +1,204 @@
+<?php
+// $Id$
+
+/**
+ * Dynamic Heading Generator
+ * By Stewart Rosenberger
+ * http://www.stewartspeak.com/headings/
+ *
+ * This script generates PNG images of text, written in
+ * the font/size that you specify. These PNG images are passed
+ * back to the browser. Optionally, they can be cached for later use. 
+ * If a cached image is found, a new image will not be generated,
+ * and the existing copy will be sent to the browser.
+ *
+ * Additional documentation on PHP's image handling capabilities can
+ * be found at http://www.php.net/image/
+ */
+
+/**
+ * Altered for Dynamic Rendering.
+ */
+function check_plain($text) {
+  return drupal_validate_utf8($text) ? htmlspecialchars($text, ENT_QUOTES) : '';
+}
+
+function drupal_validate_utf8($text) {
+  if (strlen($text) == 0) {
+    return TRUE;
+  }
+  return (preg_match('/^./us', $text) == 1);
+}
+
+$font_file = $_SERVER['DOCUMENT_ROOT'] .'/'. check_plain($_GET["font"]);
+$font_size = check_plain($_GET["size"]);
+$font_color = check_plain($_GET["color"]);
+$background_color = check_plain($_GET["bgcolor"]);
+$cache_folder = $_SERVER['DOCUMENT_ROOT'] .'/'. check_plain($_GET["cache"]);
+$transparent_background = TRUE;
+$cache_images = TRUE;
+
+/**
+ * For basic usage, you should not need to edit anything below this comment.
+ * If you need to further customize this script's abilities, make sure you
+ * are familiar with PHP and its image handling capabilities.
+ */
+
+$mime_type        = 'image/png';
+$extension        = '.png';
+$send_buffer_size = 4096;
+
+// Check for GD support.
+if (!function_exists('ImageCreate')) {
+  fatal_error('Error: Server does not support PHP image generation');
+}
+
+// Clean up text.
+if (empty($_GET['text'])) {
+  fatal_error('Error: No text specified.');
+}
+
+$text = $_GET['text'] .' ';
+if (get_magic_quotes_gpc()) {
+  $text = stripslashes($text);
+}
+$text = javascript_to_html($text);
+
+// Look for cached copy, send if it exists.
+$hash = md5(basename($font_file) . $font_size . $font_color .
+  $background_color . $transparent_background . $text
+);
+$cache_filename = $cache_folder .'/'. $hash . $extension;
+if ($cache_images && ($file = @fopen($cache_filename, 'rb'))) {
+  header('Content-type: '. $mime_type);
+  while (!feof($file)) {
+    print (($buffer = fread($file, $send_buffer_size)));
+  }
+  fclose($file);
+  exit;
+}
+
+// Check font availability.
+$font_found = is_readable($font_file);
+if (!$font_found) {
+  fatal_error('Error: The server is missing the specified font.');
+}
+
+// Create image.
+$background_rgb = hex_to_rgb($background_color);
+$font_rgb       = hex_to_rgb($font_color);
+$dip            = get_dip($font_file, $font_size);
+$box            = @ImageTTFBBox($font_size, 0, $font_file, $text);
+$image          = @ImageCreate(abs($box[2] - $box[0]), abs($box[5] - $dip));
+if (!$image || !$box) {
+  fatal_error('Error: The server could not create this heading image.');
+}
+
+// Allocate colors and draw text.
+$background_color = @ImageColorAllocate($image, $background_rgb['red'],
+  $background_rgb['green'], $background_rgb['blue']
+);
+$font_color = ImageColorAllocate($image, $font_rgb['red'],
+  $font_rgb['green'], $font_rgb['blue']
+);
+ImageTTFText($image, $font_size, 0, -$box[0], abs($box[5] - $box[3]) - $box[1],
+  $font_color, $font_file, $text
+);
+
+// Set transparency.
+if ($transparent_background) {
+  ImageColorTransparent($image, $background_color);
+}
+
+header('Content-type: '. $mime_type);
+ImagePNG($image);
+
+// Save copy of image for cache.
+if ($cache_images) {
+  @ImagePNG($image, $cache_filename);
+}
+
+ImageDestroy($image);
+exit;
+
+
+/**
+ * Try to determine the "dip" (pixels dropped below baseline) of this
+ * font for this size.
+ */
+function get_dip($font, $size) {
+  $test_chars = 'abcdefghijklmnopqrstuvwxyz' . 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' . '1234567890' . '!@#$%^&*()\'"\\/;.,`~<>[]{}-+_-=';
+  $box = @ImageTTFBBox($size, 0, $font, $test_chars);
+  return $box[3];
+}
+
+/**
+ * Attempt to create an image containing the error message given.
+ * If this works, the image is sent to the browser. If not, an error
+ * is logged, and passed back to the browser as a 500 code instead.
+ */
+function fatal_error($message) {
+  // Send an image.
+  if (function_exists('ImageCreate')) {
+    $width = ImageFontWidth(5) * strlen($message) + 10;
+    $height = ImageFontHeight(5) + 10;
+    if ($image = ImageCreate($width, $height)) {
+      $background = ImageColorAllocate($image, 255, 255, 255);
+      $text_color = ImageColorAllocate($image, 0, 0, 0);
+      ImageString($image, 5, 5, 5, $message, $text_color);
+      header('Content-type: image/png');
+      ImagePNG($image);
+      ImageDestroy($image);
+      exit;
+    }
+  }
+
+  // Send 500 code.
+  header("HTTP/1.0 500 Internal Server Error");
+  print ($message);
+  exit;
+}
+
+
+/**
+ * Decode an HTML hex-code into an array of R,G, and B values.
+ * Accepts these formats: (case insensitive) #ffffff, ffffff, #fff, fff
+ */
+function hex_to_rgb($hex) {
+  // Remove '#'.
+  if (substr($hex, 0, 1) == '#') {
+    $hex = substr($hex, 1);
+  }
+
+  // Expand short form ('fff') color.
+  if (strlen($hex) == 3) {
+    $hex = substr($hex, 0, 1) . substr($hex, 0, 1) . substr($hex, 1, 1) . substr($hex, 1, 1) . substr($hex, 2, 1) . substr($hex, 2, 1);
+  }
+  if (strlen($hex) != 6) {
+    fatal_error('Error: Invalid color "'. $hex .'"');
+  }
+
+  // Convert.
+  $rgb['red']   = hexdec(substr($hex, 0, 2));
+  $rgb['green'] = hexdec(substr($hex, 2, 2));
+  $rgb['blue']  = hexdec(substr($hex, 4, 2));
+
+  return $rgb;
+}
+
+
+/**
+ * Convert embedded, javascript unicode characters into embedded HTML
+ * entities. (e.g. '%u2018' => '&#8216;'). returns the converted string.
+ */
+function javascript_to_html($text) {
+  $matches = null;
+  preg_match_all('/%u([0-9A-F]{4})/i', $text, $matches);
+  if (!empty($matches)) {
+    for ($i = 0; $i < sizeof($matches[0]); $i++) {
+      $text = str_replace($matches[0][$i], '&#'. hexdec($matches[1][$i]) .';', $text);
+    }
+  }
+  return $text;
+}
+
Index: jitr/jquery.jitr.js
===================================================================
RCS file: jitr/jquery.jitr.js
diff -N jitr/jquery.jitr.js
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ jitr/jquery.jitr.js	13 Sep 2008 12:14:51 -0000
@@ -0,0 +1,81 @@
+// $Id$
+
+/**
+ * jQuery Image Text Replacement Alpha 1
+ * Author: Jamie Thompson (jamie_at_themagictorch_d0t_org) 
+ * Website: http://jamazon.co.uk
+ * 
+ * Copyright (c) 2008 Jamie Thompson
+ *
+ * Note: Slightly altered by Patrick Harris for Dynamic Rendering.
+ */
+(function($) {
+  $.fn.jitr = function(font, bgcolor, jitr_dir, jitr_cache) {
+    var hex = function(N) {
+      if (N==null) return "00";
+      N = parseInt(N);
+      if (N==0 || isNaN(N)) return "00";
+      N = Math.max(0, N);
+      N = Math.min(N, 255);
+      N = Math.round(N);
+      return "0123456789ABCDEF".charAt((N - N%16) / 16) + "0123456789ABCDEF".charAt(N%16);
+    };
+    
+    function hex2(s) {
+      var s = parseInt(s).toString(16);
+      return ( s.length < 2 ) ? '0'+s : s;
+    };
+    
+    function gpc(node) {
+      for (; node && node.nodeName.toLowerCase() != 'html'; node = node.parentNode) {
+        var v = jQuery.css(node,'backgroundColor');
+        if (v.indexOf('rgb') >= 0) {
+          rgb = v.match(/\d+/g); 
+          return hex2(rgb[0]) + hex2(rgb[1]) + hex2(rgb[2]);
+        }
+        if (v && v != 'transparent') {
+          return v;
+        }
+      }
+      return 'ffffff';
+    };
+    
+    var hexed = function(color) {
+      if (!color) {
+        return false;
+      };
+      if (color.search('rgb') > -1) {
+        color = color.substr(4,color.length-5).split(', ');
+        color = hex(color[0]) + hex(color[1]) + hex(color[2]);
+      };
+      color = color.replace('#','');
+      if (color.length < 6) {
+        color = color.substr(0, 1)
+          + color.substr(0, 1)
+          + color.substr(1, 1)
+          + color.substr(1, 1)
+          + color.substr(2, 1)
+          + color.substr(2, 1);
+      };
+      return color;
+    };
+    
+    return $(this).each(function() {
+      if (!$(this).children().length) {
+        bgcolor = bgcolor ? bgcolor : gpc(this.parentNode);
+        var color = hexed($(this).css('color'));
+        var size = parseInt($(this).css('font-size'));
+        //if($.browser.msie) size = Math.round(size / 1.7) /* why microsoft WHY? */
+        var words = $(this).text().split(' ');
+        $(this).html('');
+        
+        for (i = 0; i < words.length; i++) {
+          $(this).append('<img alt="' + words[i] + '" src="/' + jitr_dir + '/heading.php?text='
+          + escape(words[i]) + '&color=' + color + '&bgcolor=' + bgcolor
+          + '&size=' + size + '&font=' + font + '&cache=' + jitr_cache + '">');
+        };
+      };
+      $(this).css('visibility','visible');
+    });
+  };
+})(jQuery);
Index: plugins/jitr-README.txt
===================================================================
RCS file: plugins/jitr-README.txt
diff -N plugins/jitr-README.txt
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ plugins/jitr-README.txt	13 Sep 2008 12:10:05 -0000
@@ -0,0 +1,18 @@
+/* $Id: sifr-README.txt,v 1.1.2.5 2008/02/24 04:44:35 sun Exp $ */
+
+-- INSTALLATION --
+
+* Upload your .ttf or .otf font files at admin/settings/render/manage
+
+
+-- CREDITS --
+
+jITR Dynamic Rendering plugin written by Patrick Harris.
+
+Based on
+* jQuery jITR script by Jamie Thompson
+  http://jamazon.co.uk/projects/2008/03/17/jquery-image-text-replacement-work-in-progress
+* Dynamic Text Replacement by Stewart Rosenberger
+  http://www.alistapart.com/articles/dynatext
+
+
Index: plugins/jitr.inc
===================================================================
RCS file: plugins/jitr.inc
diff -N plugins/jitr.inc
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ plugins/jitr.inc	13 Sep 2008 12:29:31 -0000
@@ -0,0 +1,247 @@
+<?php
+// $Id$
+
+
+/**
+ * @file
+ * Dynamic Rendering plugin for jQuery jITR.
+ */
+
+/**
+ * Return plugin information.
+ *
+ * @return array
+ *   An array containing the keys
+ *   - type: The type of this plugin. @see render_get_types().
+ *   - name: The filename of this plugin (internal). Also used to display a
+ *     plugin image in plugins/<name>.png.
+ *   - title: The official title of this plugin.
+ *   - url: An URI of the website of this plugin.
+ *   - dependencies: An array of filenames that have to exist in the plugin
+ *     folder.
+ *   - file_masks: An array containing regular expressions matching
+ *     corresponding font files.
+ *   - properties: An array of plugin-specific properties to store in the
+ *     database.
+ */
+function jitr_render_info() {
+  return array(
+    'type' => 'text',
+    'name' => 'jitr',
+    'title' => 'jitr',
+    'url' => 'http://jamazon.co.uk/projects/2008/03/17/jquery-image-text-replacement-work-in-progress',
+    'dependencies' => array('jquery.jitr.js', 'heading.php'),
+    'file_masks' => array('.+\.ttf$', '.+\.otf$'),
+    'properties' => array('font', 'bgcolor'),
+  );
+}
+
+/**
+ * Return plugin help on render/manage.
+ *
+ * @return string
+ *   A translatable string instructing the user how to use this plugin or
+ *   an empty string to hide plugin instructions.
+ */
+function jitr_render_help() {
+  return t('<p>Upload any ttf or otf (True Type Font or Open Type Font) font file here.</p>');
+}
+
+/**
+ * Perform plugin installation checks executed on render/addrule.
+ */
+function jitr_render_setup() {
+  // Check or create working 'render' directory in files folder.
+  $dir = file_create_path('render');
+  if (!file_check_directory($dir, 1)) {
+    drupal_set_message(t('The jitr working directory !dir is not writable.', array('!dir' => $dir)), 'error');
+    return FALSE;
+  }
+  // Check or create cache directory.
+  $dir = file_create_path('render/jitrcache');
+  if (!file_check_directory($dir, 1)) {
+    drupal_set_message(t('The jitr cache directory !dir is not writable.', array('!dir' => $dir)), 'error');
+    return FALSE;
+  }
+  return TRUE;
+}
+
+/**
+ * Returns font(s) and colors of a text replacement rule.
+ *
+ * @param array $rule
+ *   A text replacement rule.
+ *
+ * @return array $fontstyle
+ *   An array containing the keys
+ *   - font
+ *   - bgcolor
+ */
+function jitr_render_rules($rule) {
+  $fontstyle = array();
+  $fontstyle['font'] = $rule['font'];
+  $fontstyle['bgcolor'] = $rule['bgcolor'];
+  // Necessary to add this line, or API throws an error.
+  $fontstyle['colors'] = array();
+  return $fontstyle;
+}
+
+/**
+ * Return custom rule properties.
+ *
+ * @param array $form
+ *   A rule edit form, passed by reference.
+ * @param array $edit
+ *   User values for the form.
+ */
+function jitr_render_rule(&$form, $edit) {
+  $form['font'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('Font'),
+  );
+  $form['font']['font'] = array(
+    '#title' => t('Font'),
+    '#type' => 'item',
+    '#description' => t("Select a font to use for this rule."),
+    '#required' => TRUE,
+  );
+  $form['font']['font']['fonts'] = render_font_select($edit, 'font');
+
+  $form['color'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('Colors'),
+    '#collapsible' => FALSE,
+    '#collapsed' => FALSE,
+    '#description' => t('Use a hexadecimal (CSS-style) color value preceeded by &quot;<code>#</code>&quot; to define background color. Text color will be set automatically.'),
+  );
+  $form['color']['bgcolor'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Background Color'),
+    '#size' => 12,
+    '#default_value' => $edit['bgcolor'] ? $edit['bgcolor'] : '#ffffff',
+  );
+}
+
+/**
+ * Render a single Javascript text replacement rule.
+ *
+ * @param array $rule
+ *   A user-generated rule either containing custom rule properties or
+ *   a default rule containing the keys selector, font, color, linkcolor,
+ *   hovercolor, bgcolor and fontsize as they are needed for font preview
+ *   in rule setup.
+ * @see render_edit_rule();
+ *
+ * @return string
+ *   A single rendered JavaScript rule for this plugin.
+ */
+function jitr_render_render_rule_js($rule) {
+  $properties = array();
+  // Convert spaces in filename.
+  $fontpath = base_path() . str_replace('%2F', '/', rawurlencode($rule['font']));
+  $properties['font'] = $fontpath;
+  $properties['bgcolor'] = $rule['bgcolor'];
+  // Remove '#' from color.
+  if (substr($properties['bgcolor'], 0, 1) == '#') {
+    $properties['bgcolor'] = substr($properties['bgcolor'], 1);
+  }
+  $jitr_dir   = render_find_render('jitr') .'/heading.php';
+  $jitr_cache = file_directory_path() .'/render/jitrcache';
+  $output     = '$("'. $rule['selector'] .'").jitr("'. $properties['font'] .'", "'. $properties['bgcolor'] .'", "'. $jitr_dir .'", "'. $jitr_cache .'");';
+
+  return $output;
+}
+
+/**
+ * Wrap execution handler around JavaScript rules.
+ *
+ * @param array $rules
+ *   An array of all current rules for this plugin with already rendered
+ *   JavaScript string in each element.
+ *
+ * @return string
+ *   A complete JavaScript to execute this plugin.
+ */
+function jitr_render_wrap_rules($rules) {
+  $output = '';
+  if (is_array($rules)) {
+    $output .= "jQuery(document).ready(function() {\n";
+    foreach ($rules as $rule) {
+      $output .= '  '. $rule ."\n";
+    }
+    $output .= "  $('.content img').each(function() {\n";
+    $output .= "    if ($(this).attr('align')) {\n";
+    $output .= "      $(this).addClass($(this).attr('align'));\n";
+    $output .= "    }\n";
+    $output .= "  });\n";
+    $output .= "});\n";
+  }
+  return $output;
+}
+
+/**
+ * Render a CSS file for this plugin.
+ *
+ * @param array $rule
+ *   A user-generated rule either containing custom rule properties or
+ *   a default rule containing the keys selector, font, color, linkcolor,
+ *   hovercolor, bgcolor and fontsize as they are needed for font preview
+ *   in rule setup.
+ * @see render_edit_rule();
+ *
+ * @return string
+ *   A stylesheet for this plugin.
+ */
+function jitr_render_css_screen($rules) {
+  $output = "
+/* These jitr \"decoy\" styles are used to hide the browser text before it is replaced. */ 
+";
+  $count = 0;
+  foreach ($rules as $rule) {
+    if ($count) {
+      $output .= ', ';
+    }
+    $output .= 'html.js '. $rule['selector'];
+    $count++;
+  }
+  $output .= " {
+  visibility: hidden;
+}
+";
+  return $output;
+}
+
+/**
+ * Load plugin JavaScript and stylesheet files.
+ *
+ * Perform all necessary actions to load this plugin on all pages.
+ */
+function jitr_render_load() {
+  $plugindir = render_find_render('jitr');
+  if (!$plugindir) {
+    $info        = jitr_render_info();
+    $link_jitr   = l($info['title'], $info['url']);
+    $link_readme = l('jitr-README.txt', drupal_get_path('module', 'render') .'/plugins/jitr-README.txt');
+    drupal_set_message(t('The jitr library is not installed correctly. Please download it from !link and follow installation instructions in !readme.', array('!link' => $link_jitr, '!readme' => $link_readme)), 'error');
+  }
+  else {
+    drupal_add_js($plugindir .'/jquery.jitr.js');
+  }
+}
+
+/**
+ * Delete all files in the jitr cache directory.
+ *
+ * Note: Not sure where to put this yet, so at the moment it is not used.
+ */
+function _jitr_delete() {
+  $path = file_directory_path() .'/render/jitrcache';
+  $listing = $path .'/*';
+  foreach (glob($listing) as $file) {
+    if (is_file($file) === TRUE) {
+      @unlink($file);
+    }
+  }
+  return;
+}
+
