Branch: Tag:

2015-10-23

2015-10-23 13:54:40 by Henrik Grubbström (Grubba) <grubba@grubba.org>

Merge commit '8a2ce4a87' into patches/bug7582

* commit '8a2ce4a87': (7413 commits)

1: - // This is a roxen module. Copyright © 1996 - 2000, Roxen IS. + // This is a roxen module. Copyright © 1996 - 2009, Roxen IS.   //    - constant cvs_version="$Id: graphic_text.pike,v 1.275 2001/08/23 21:20:59 nilsson Exp $"; + constant cvs_version="$Id$";      #include <module.h>   inherit "module";
37:    TYPE_FLAG|VAR_MORE|VAR_NOT_CFIF,    "Append the image format (.gif, .png, .jpg, etc) to the generated "    "images. This is not necessary, but might seem nicer."); +  defvar("honor_supports", 1, "Honor supports", +  TYPE_FLAG|VAR_MORE, +  "Normally javascript tags generated by the 'magic' attribute are not " +  "sent to clients that don't support javascript image objects. " +  "This check can be disabled to always output those javascript tags.");   }      TAGDOCUMENTATION;
69: Inside #if defined(manual)
     <attr name='bevel' value='width'><p>    Draws a bevel-box around the text.</p> -  <ex type=vert> +  <ex>   <gtext bevel=\"2\">Ok</gtext>    </ex>   </attr>
81: Inside #if defined(manual)
      <p>If you set the background color, it is probably best to add the    notrans attribute as well.</p> -  <ex type=vert> +  <ex>   <gtext notrans=\"\" bgcolor=\"pink\">Pink</gtext>   <gtext notrans=\"\" bgcolor=\"#ff0000\">Red</gtext>   <gtext notrans=\"\" bgcolor=\"%50,0,100,0\">%50,0,100,0</gtext>
95: Inside #if defined(manual)
  <attr name='bold'><p>    Use a bold version of the font, if available. Can not be used    together with the black or light attributes.</p> - <ex type=hor> + <ex>   <gtext font='lucida'>Aa3</gtext><br />   <gtext font='lucida' bold=''>Aa3</gtext><br />   <gtext font='lucida' italic=''>Aa3</gtext><br />
122: Inside #if defined(manual)
   does not currently place the shadow directly below the text. Using    negative values for distance is possible, but you might have to add    'spacing'.</p> -  <ex type=vert> +  <ex>   <gtext scale=\"0.8\" fgcolor=\"#FF6600\"   bshadow=\"1\">&lt;gtext bshadow=1&gt;</gtext>   <br /><gtext scale=\"0.8\" fgcolor=\"#FF6600\"
132: Inside #if defined(manual)
     <attr name='chisel'><p>    Make the text look like it has been cut into the background.</p> -  <ex type=vert> +  <ex>   <gtext font=\"lucida\" bold=\"\" chisel=\"\" talign=\"center\" tile=\"\"   opaque=\"70\" fgcolor=\"gold\" bevel=\"2\"   background=\"/internal-roxen-squares\"> Chisel opaque=\"70\"</gtext>
153: Inside #if defined(manual)
     <attr name='fgcolor' value='color'><p>    Sets the text color.</p> -  <ex type=vert> +  <ex>   <gtext fgcolor=\"#0080FF\">#0080FF</gtext>    </ex>   </attr>
182: Inside #if defined(manual)
  <attr name='ghost' value='dist,blur,color'><p>    Apply a ghost effect. Cannot be used together with shadow or magic    coloring.</p> -  <ex type='vert'><gtext spacing=\"2\" crop=\"\" ghost=\"1,1,red\">ghost=1,1,red</gtext></ex> +  <ex><gtext spacing=\"2\" crop=\"\" ghost=\"1,1,red\">ghost=1,1,red</gtext></ex>   </attr>      <attr name='glow' value='color'><p>    Apply a 'glow' filter to the image. Quite a CPU eater. Looks much    better on a dark background, where a real 'glow' effect can be    achieved.</p> -  <ex type=vert> +  <ex>   <gtext glow=\"red\">&lt;gtext glow=red&gt;</gtext>    </ex>   </attr>
211: Inside #if defined(manual)
  <attr name='notrans'><p>    Do not make the background transparent. Useful when making 'boxes' of    color around the text.</p> -  <ex type=vert> +  <ex>   <gtext bgcolor=\"red\">&lt;gtext bgcolor=red&gt;</gtext><br />   <gtext bgcolor=\"red\" notrans=\"\">&lt;gtext   bgcolor=red notrans&gt;</gtext>
226: Inside #if defined(manual)
   Sets the 'opaque' value of the color used to draw the text. Default    is 100%. In the example below, notice how the text color mixes with    the two background colors.</p> -  <ex type=vert> +  <ex>   <gtext scale=\"0.6\" textbox=\"100,pink,-11\" bgcolor=\"lightblue\"   notrans=\"\" opaque=\"40\" fgcolor=\"black\"   >&lt;Demonstration of opaque text&gt;</gtext>
236: Inside #if defined(manual)
  <attr name='outline' value='color,extra-radius'><p>    Draw an outline around the text. Quite useful when combined with    textscale.</p> -  <ex type=vert> +  <ex>   <gtext xspacing=\"4\" quant=\"128\" textscale=\"red,red,yellow,yellow\"   outline=\"black,1\"   >black, 2 pixels</gtext>
256: Inside #if defined(manual)
   is quite useless. It is advisable to use powers of 2 to optimize the    palette allocation.</p>    -  <ex type=vert> +  <ex>   <gtext quant=\"2\">A</gtext>   <gtext quant=\"6\">A</gtext>   <gtext quant=\"20\">A</gtext>
274: Inside #if defined(manual)
     <attr name='scale' value='number'><p>    Sets the scale of the image. Larger than 1.0 is enlargement.</p> -  <ex type=vert> +  <ex>   <gtext scale=\"1.0\">&lt;gtext scale=1.0&gt;</gtext>   <gtext scale=\"0.5\">&lt;gtext scale=0.5&gt;</gtext>    </ex>
292: Inside #if defined(manual)
   Draw a blured black drop-shadow behind the text. Using 0 as distance    does not currently place the shadow directly below the text. Using negative    values for distance is possible,</p> -  <ex type=vert><gtext scale=\"0.8\" fgcolor=\"blue\" +  <ex><gtext scale=\"0.8\" fgcolor=\"blue\"   shadow=\"40,0\">&lt;gtext shadow=40,0&gt;</gtext>   <br /><gtext scale=\"0.8\" fgcolor=\"blue\"   shadow=\"40,2\">&lt;gtext shadow=40,2&gt;</gtext></ex>
313: Inside #if defined(manual)
  <attr name='textbelow' value='color'><p>    Place the text centered in a box of the given color below the image    area. Useful together with background to make captions for images.</p> -  <ex type=vert> +  <ex>   <img src=\"/internal-roxen-roxen\" /> &nbsp;   <gtext scale=\"0.5\" background=\"/internal-roxen-roxen\"   textbelow=\"#c0c0c0\">Roxen</gtext>
329: Inside #if defined(manual)
   respectively, upper left, lower left, upper right and lower right.    It is probably a good idea to increase the 'quant' value when    using this argument.</p> -  <ex type=vert> +  <ex>   <gtext quant=\"128\" textscale=\"blue,white,red,darkgreen\"   >Blue, white,   red, darkgreen</gtext>
338: Inside #if defined(manual)
     <attr name='texture' value='path'><p>    Uses the specified images as a field texture.</p> - <ex type=hor> - <gtext font=\"\" fontsize=\"100\" - texture=\"/internal-roxen-squares\">A</gtext> + <ex> + <gtext texture=\"/internal-roxen-squares\" +  tile=\"1\" fontsize=\"100\">A</gtext>   </ex>   </attr>    - <attr name=tile> -  Tiles the background and foreground images if they are smaller than -  the actual image. + <attr name='tile'> +  <p>Tiles the background and foreground images if they are smaller than +  the actual image.</p>   </attr>    - <attr name='xpad' value='percentage|integer'><p> + <attr name='xpad' value='percentage|integer ended with \"px\"'><p>    Sets the padding between characters. The value can either be an -  relative change, in percent, or an absolute value. Note that +  relative change, in percent, or an absolute number of pixels, ended +  with the string \"px\". Note that    different fonts reacts differently on these values and for some it    will not have any effect at all. This depends on the type of the font    and the font implementation.</p>    - <ex type='vert'> + <ex>   <gtext font=\"niquel\">HELLO ROXEN</gtext><br /> - <gtext xpad=\"4\" font=\"niquel\">HELLO ROXEN</gtext><br /> + <gtext xpad=\"4px\" font=\"niquel\">HELLO ROXEN</gtext><br />   <gtext xpad=\"50%\" font=\"niquel\">HELLO ROXEN</gtext><br />   </ex>   </attr>
371: Inside #if defined(manual)
   Sets the horizontal spacing.</p>   </attr>    - <attr name='ypad' value='percentage'><p> -  Sets the padding beteen lines.</p> + <attr name='ypad' value='percentage|integer ended with \"px\"'><p> +  Sets the padding beteen lines. Works as xpad.</p>   </attr>      
382: Inside #if defined(manual)
     <attr name='yspacing' value='number'><p>    Sets the vertical spacing.</p> + </attr> +  + <h1>Timeout</h1> +  + <p>The generated image will by default never expire, but + in some circumstances it may be pertinent to limit the + time the image and its associated data is kept. Its + possible to set an (advisory) timeout on the image data + using the following attributes.</p> +  + <attr name='unix-time' value='number'><p> + Set the base expiry time to this absolute time.</p><p> + If left out, the other attributes are relative to current time.</p> + </attr> +  + <attr name='years' value='number'><p> + Add this number of years to the time this entry is valid.</p> + </attr> +  + <attr name='months' value='number'><p> + Add this number of months to the time this entry is valid.</p> + </attr> +  + <attr name='weeks' value='number'><p> + Add this number of weeks to the time this entry is valid.</p> + </attr> +  + <attr name='days' value='number'><p> + Add this number of days to the time this entry is valid.</p> + </attr> +  + <attr name='hours' value='number'><p> + Add this number of hours to the time this entry is valid.</p> + </attr> +  + <attr name='beats' value='number'><p> + Add this number of beats to the time this entry is valid.</p> + </attr> +  + <attr name='minutes' value='number'><p> + Add this number of minutes to the time this entry is valid.</p> + </attr> +  + <attr name='seconds' value='number'><p> + Add this number of seconds to the time this entry is valid.</p>   </attr>";         constant tagdoc=([ - "anfang":#"<desc cont='cont'><p><short> + "anfang":#"<desc type='cont'><p><short>    Creates an anfang in the beginning of a text.</short> This tag takes    the same attributes as <xref href='gtext.tag' />.</p>    -  <ex type=vert> +  <ex>    <anfang crop=\"\">This is a beginning<br />    of a very short text,<br />    and here it ends.
399: Inside #if defined(manual)
  </desc>   <noex>"+gtextargs+"</noex>",    - "gh":#"<desc cont='cont'><p><short> + "gh":#"<desc type='cont'><p><short>    Creates a graphical header.</short> <tag>gh</tag> takes the same    attributes as <xref href='gtext.tag' />. <tag>gh</tag> comes in six    flavors, from <tag>gh1</tag> through <tag>gh6</tag> and are the RXML
407: Inside #if defined(manual)
  </desc>   <noex>"+gtextargs+"</noex>",    - "gh1":#"<desc cont='cont'></desc> + "gh1":#"<desc type='cont'></desc>   <noex>"+gtextargs+"</noex>",    - "gh2":#"<desc cont='cont'></desc> + "gh2":#"<desc type='cont'></desc>   <noex>"+gtextargs+"</noex>",    - "gh3":#"<desc cont='cont'></desc> + "gh3":#"<desc type='cont'></desc>   <noex>"+gtextargs+"</noex>",    - "gh4":#"<desc cont='cont'></desc> + "gh4":#"<desc type='cont'></desc>   <noex>"+gtextargs+"</noex>",    - "gh5":#"<desc cont='cont'></desc> + "gh5":#"<desc type='cont'></desc>   <noex>"+gtextargs+"</noex>",    - "gh6":#"<desc cont='cont'></desc> + "gh6":#"<desc type='cont'></desc>   <noex>"+gtextargs+"</noex>",    - "gtext":#"<desc cont='cont'><p><short> + "gtext":#"<desc type='cont'><p><short>    Creates an image with the tag content texts.</short> It is possible to pass    attributes, such as the target attribute, to the resulting tags by including    them in the gtext tag.</p>
436: Inside #if defined(manual)
   default the alt attribute will be set to the contents of the    <tag>gtext</tag> tag.</p>    -  <ex type=vert> +  <ex>    <gtext fgcolor=\"blue\" alt=\"Hello!\">Welcome!</gtext>    </ex>   </attr>
444: Inside #if defined(manual)
  <attr name='border' value='width,color'><p>    Draws a border around the text of the specified width and color.</p>    -  <ex type=vert> +  <ex>   <gtext fgcolor=\"blue\" border=\"2,red\">Red border</gtext>    </ex>   </attr>
460: Inside #if defined(manual)
   will highlight the image when the mouse is moved over it. The message    is shown in the browser's status bar.</p>    -  <ex type=vert> +  <ex>   <gtext href=\"http://www.roxen.com\" magic=\"Roxen\">www.roxen.com</gtext>    </ex>   </attr>
469: Inside #if defined(manual)
   Same as for any <tag>gtext</tag> attribute, except for the    highlighted image.</p>    - <ex type=vert><gtext fgcolor=\"blue\" magic=\"\" - magic-glow=\"red\" magic-fg=\"white\">Mouse me!</gtext></ex> + <ex><gtext fgcolor=\"blue\" magic=\"\" + magic-glow=\"red\" magic-fgcolor=\"white\">Mouse me!</gtext></ex>   </attr>      <attr name='noxml'><p>
482: Inside #if defined(manual)
   writing a large text, and word wrap at the edges of the display is    desired.</p>    - <ex type='vert'> + <ex>    <gtext scale='0.4' split='split'>    Useful if you are writing a large text, and word wrap at the edges    of the display is desired.
494: Inside #if defined(manual)
   wraping functionality of this example cannot be shown as the size of    the browser window is determined by the largest example box. </p>    -  <ex type='vert'><gtext scale=\"0.4\" split=\"\">One image per character.</gtext></ex> +  <ex><gtext scale=\"0.4\" split=\"\">One image per character.</gtext></ex>   </attr>      <attr name='submit'><p>
518: Inside #if defined(manual)
   but if you would like to generate new text images live without    reloading some RXML page, you need this tag. An example application:</p>    - <ex type='live'> - <define variable='var.id' preparse='' trimwhites=''> + <ex-box><define variable='var.id' preparse='' trimwhites=''>   <gtext-id font='FranklinGothicDemi' fgcolor='blue'/>   </define>      <img src='&var.id;Please type some text here:' -  alt='' name='banner' width='468' height='60'/> +  alt='' name='banner' width='468' height='60' />      <script language='javascript'>   var image = document.images.banner;
538: Inside #if defined(manual)
     <form onsubmit='return alter_image(this.label);'>   <input type='text' size='40' name='label' /> - </form></ex> - </desc> + </form></ex-box></desc>      <attr name='short'><p>    Returns a relative path to the image, i.e. a shorter one.   </p>   </attr>"+gtextargs,    - "gtext-url":#"<desc cont='cont'><p><short> + "gtext-js":#"<desc tag='tag'><p><short> +  Inserts javascript funcations that are used by gtext when using +  the magic attributes.</short> +  This is normally inserted at the first instance of a gtext, but it may +  be necessary to insert the gtext using this tag if the first gtext in a page +  may be hidden, for example if contained in an if tag. +  </p> + </desc>", +  + "gtext-url":#"<desc type='cont'><p><short>    Returns an internal URL to an image with the specified attributes    applied.</short></p>   </desc>
563:      private roxen.ImageCache image_cache;   private string compat_level; + private int honor_supports;      string status() {    array s=image_cache->status();
572:   }      mapping(string:function) query_action_buttons() { -  return ([ "Clear cache":flush_cache ]); +  return ([ "Clear Cache":flush_cache ]);   }      void flush_cache() {
585:    roxen.dump( "etc/modules/GText.pmod" );    if(query("colorparse")) module_dependencies(conf, ({ "wiretap" }) );    compat_level = conf->query("compat_level"); +  honor_supports = query("honor_supports");   }    -  + void stop() + { +  destruct(image_cache); + } +    private constant nbsp = Roxen.iso88591["&nbsp;"];      private Image.Image|mapping draw_callback(mapping args, string text, RequestID id)
663:       int|float xpad=0.0;    if(args->xpad) -  if(args->xpad[-1]=='%') -  xpad = (float)args->xpad; -  else +  if(args->xpad[-1]=='x' && args->xpad[-2]=='p')    xpad = (int)args->xpad; -  +  else +  xpad = (float)args->xpad;       int|float ypad=0.0;    if(args->ypad) -  if(args->ypad[-1]=='%') -  ypad = (float)args->ypad; -  else +  if(args->ypad[-1]=='x' && args->ypad[-2]=='p')    ypad = (int)args->ypad; -  +  else +  ypad = (float)args->ypad;       font = get_font(args->font,    (int)args->fontsize||32,
689:    (args->afont||args->font||args->nfont)+ ")!\n");       // Fonts and such are now initialized. -  [img, Image.Image alpha] = GText.make_text_image(args, font, text, id); +  array|mapping make_res = GText.make_text_image(args, font, text, id); +  if (mappingp(make_res)) +  return make_res; +  [img, Image.Image alpha] = make_res;       // Now we have the image in 'img'.   
704:       if(args->fadein)    { -  int amount=2, steps=10, delay=10, initialdelay=0, ox; +  int amount=2, steps=10, delay=10, initialdelay=0;    string res = img->gif_begin();    sscanf(args->fadein,"%d,%d,%d,%d", amount, steps, delay, initialdelay);    if(initialdelay)
759:    {    array id_text = f/"/";    if( sizeof(id_text)==2 ) -  { // It's a gtext-id -  string second_key = roxen->argcache->store( (["":id_text[1]]) ); -  return image_cache->http_file_answer( id_text[0][1..] +"$"+ second_key, id ); +  { // It's a gtext-id, let it live for an hour. +  string second_key = roxen->argcache->store( (["":id_text[1]]), 3600 ); +  return image_cache->http_file_answer( id_text[0][1..] +"$"+ second_key, +  id, UNDEFINED, 3600 );    }    }    return image_cache->http_file_answer( f, id ); -  return 0; +    }      
783:   private constant textarg = ({    "afont",    "alpha", +  "baselineoffset",    "bevel",    "bgcolor",    "bgturbulence",
802:    "mirrortile",    "move",    "narrow", +  "no-auto-alpha",    "notrans",    "opaque",    "outline", -  +  "oversampling",    "pressed",    "rescale",    "rotate",
842:      private constant hreffilter = ([ "split":1, "magic":1, "noxml":1, "alt":1 ]);    + string gtext_javascript(RequestID id) { +  string res=""; +  if(!id->root_id->misc->gtext_magic_java) { +  res += "function gtext_mo(ri,hi,txt)\n" +  "{\n" +  " document.images[ri].src = hi.src;\n" +  " if( txt != 0 )\n" +  " setTimeout(\"top.window.status = '\"+txt+\"'\", 100);\n" +  "}"; +  id->root_id->misc->gtext_magic_java="yes"; +  } +  return res; + } +  + private int get_file_stat( string f, RequestID id ) + { +  int res; +  mapping stat_cache; +  +  // -1 is used to cache negative results. When SiteBuilder crawler runs +  // we must let the stat_file() run unconditionally to register +  // dependencies properly. +  if (stat_cache = id->misc->gtext_statcache) { +  if (!id->misc->persistent_cache_crawler) +  if (res = stat_cache[f]) +  return (res > 0) && res; +  } else +  stat_cache = id->misc->gtext_statcache = ([ ]); +  +  int was_internal = id->misc->internal_get; +  id->misc->internal_get = 1; +  res = stat_cache[ f ] = (id->conf->stat_file( f,id ) || +  ({ 0,0,0,0 }) )[ST_MTIME] || -1; +  if (!was_internal) +  m_delete(id->misc, "internal_get"); +  return (res > 0) && res; + } +    private mapping mk_gtext_arg(mapping arg, RequestID id)   {    mapping p=([]); //Picture rendering arguments.
873:   #endif       foreach(filearg, string tmp) -  if(arg[tmp]) +  if(string path = arg[tmp])    { -  p[tmp]=Roxen.fix_relative(arg[tmp],id); -  m_delete(arg,tmp); +  // Reject empty file paths for sufficiently high compat_level +  if (path == "" && compat_level >= "5.2") +  RXML.parse_error("Empty " + tmp + " attribute not allowed."); +  +  if (!has_prefix(tmp, "magic-")) { +  p[tmp] = Roxen.fix_relative(path, id); +  p[tmp + "_stat"] = get_file_stat(path, id); + #if constant(Sitebuilder) +  // The file we called get_file_stat() on above may be a SiteBuilder +  // file. If so we need to extend the argument data with e.g. +  // current language fork. +  if (Sitebuilder.sb_prepare_imagecache) +  p = Sitebuilder.sb_prepare_imagecache(p, path, id); + #endif +  m_delete(arg, tmp); +  } else { +  // The magic-* attributes will be removed later. +  arg[tmp]=Roxen.fix_relative(arg[tmp],id);    } -  +  }      // if(arg->border && (search(arg->border,",")!=-1))   // {
920:    else {    string font = p->font;    p->font = roxen->fonts->verify_font(p->font, p->fontsize||32); -  if(!p->font) RXML.parse_error("Font "+font+" could not be loaded.\n"); +  if(!p->font) { +  RXML.parse_error("Font " + (font || roxen->query("default_font")) + +  " could not be loaded.\n");    } -  +  }       return p;   }
937:    m_delete(m, "noparse");    m_delete(m, "preparse");    -  c=replace(c, Roxen.replace_entities+({" "," ", "\n\n\n", "\n\n", "\r"}), -  Roxen.replace_values+({" ", " ", "\n", "\n", ""})); +  c=replace(c, Roxen.replace_entities + ({ +  " ", " ", +  "\n\n\n", "\n\n", +  "\r\n\r\n\r\n", "\r\n\r\n", "\r\n", +  "\r\r\r", "\r\r", "\r" +  }), +  Roxen.replace_values + ({ +  " ", " ", +  "\n", "\n", +  "\n", "\n", "\n", +  "\n", "\n", "\n", +  }));       if(m->maxlen)    c = c[..(( (int)m_delete(m,"maxlen") || query("deflen"))-1)];
957:    class Frame {    inherit RXML.Frame;    array do_return(RequestID id) { -  content=fix_text(content,args,id); +  int timeout = Roxen.timeout_dequantifier(args); +  content=fix_text(content||"",args,id);    mapping p=mk_gtext_arg(args,id);    if(args->href && !p->fgcolor) p->fgcolor=id->misc->gtext_link||"#0000ff";    string ext="";    if(query("ext")) ext="."+(p->format || "gif");    if(!args->short)    return ({ query_absolute_internal_location(id) + -  image_cache->store( ({p,content}), id )+ext }); -  return ({ "+"+image_cache->store( ({p,content}), id )+ext }); +  image_cache->store( ({p,content}), id, timeout )+ext }); +  return ({ "+"+image_cache->store( ({p,content}), id, timeout )+ext });    }    }   }    -  + class TagGTextJS { +  inherit RXML.Tag; +  constant name = "gtext-js"; +  constant flags = RXML.FLAG_EMPTY_ELEMENT; +  +  class Frame { +  inherit RXML.Frame; +  +  array do_return(RequestID id) { +  return ({ gtext_javascript(id) }); +  } +  } + } +    class TagGTextID {    inherit RXML.Tag;    constant name = "gtext-id";
979:    inherit RXML.Frame;       array do_return(RequestID id) { +  int timeout = Roxen.timeout_dequantifier(args);    mapping p=mk_gtext_arg(args,id);    if(args->href && !p->fgcolor) p->fgcolor=id->misc->gtext_link||"#0000ff";    if(!args->short)    return ({ query_absolute_internal_location(id) + -  "$"+image_cache->store(p, id)+"/" }); -  return ({ "+"+image_cache->store(p, id )+"/foo" }); +  "$"+image_cache->store(p, id, timeout)+"/" }); +  return ({ "+"+image_cache->store(p, id, timeout)+"/foo" });    }    }   }
1003:    }   }    + #ifdef GTEXT_RANDOM_PREFIX + constant random_chars = "abcdefghijklmnopqrstuvwxyz" / ""; +  + string random_pfx() { +  string s = ""; +  for(int i=0; i < 4; i++) +  s += random_chars[random(sizeof(random_chars))]; +  return s; + } +  + string get_gtext_pfx(RequestID id) { +  if(!id->root_id->misc->gtext_pfx) { +  id->root_id->misc->gtext_pfx = random_pfx(); +  RXML_CONTEXT->set_root_id_misc("gtext_pfx", id->root_id->misc->gtext_pfx); +  } +  return id->root_id->misc->gtext_pfx; + } + #endif +    private string do_gtext(mapping arg, string c, RequestID id)   {    if((c-" ")=="") return "";    -  id = id->root_id; -  +     c=fix_text(c,arg,id);    mapping p=mk_gtext_arg(arg,id);   
1045:       int xml=!m_delete(arg, "noxml");    -  if(!arg->border) arg->border="0"; +  // No border should be used for <img>. Force CSS declaration to avoid +  // borders when gtext is clickable. +  m_delete(arg, "border"); +  arg->style = "border: none;" + (arg->style || "");    -  +  int timeout = Roxen.timeout_dequantifier(arg); +  int no_draw = !id->misc->generate_images;    if(arg->split)    {    string res="",split=arg->split;
1056:    int setalt=!arg->alt;    foreach(c/split-({""}), string word)    { -  string fn = image_cache->store( ({ p, word }),id ); -  mapping size = image_cache->metadata( fn, id, 1 ); +  string fn = image_cache->store( ({ p, word }), id, timeout ); +  mapping size = image_cache->metadata( fn, id, no_draw, timeout);    if(setalt) arg->alt=word;    arg->src=query_absolute_internal_location(id)+fn+ext;    if( size )
1065:    arg->width = (string)size->xsize;    arg->height = (string)size->ysize;    } +  else { +  m_delete (arg, "width"); +  m_delete (arg, "height"); +  }    res+=Roxen.make_tag( "img", arg, xml )+" ";    }    return sprintf(lp,res);    }    -  string num = image_cache->store( ({ p, c }), id ); -  mapping size = image_cache->metadata( num, id, 1 ); +  string num = image_cache->store( ({ p, c }), id, timeout ); +  mapping size = image_cache->metadata( num, id, no_draw, timeout );    if(!arg->alt) arg->alt=replace(c,"\"","'");       arg->src=query_absolute_internal_location(id)+num+ext;
1088:       m_delete(p, "fgcolor");    foreach(glob("magic-*", indices(arg)), string q) -  p[q[6..]]=arg[q]; +  p[q[6..]]=m_delete(arg, q);       if(!p->fgcolor) p->fgcolor=id->misc->defines->theme_alink||    id->misc->defines->alink||"#ff0000";    -  string num2 = image_cache->store( ({ p, c }),id ); -  size = image_cache->metadata( num2, id ); +  string num2 = image_cache->store( ({ p, c }), id, timeout ); +  size = image_cache->metadata( num2, id, UNDEFINED, timeout );    if(size) {    arg->width=(string)max(arg->xsize,size->xsize);    arg->height=(string)max(arg->ysize,size->ysize);    }    -  if(!id->supports->images) return sprintf(lp,arg->alt); + #ifdef GTEXT_RANDOM_PREFIX +  string sn = "gtext" + get_gtext_pfx(id) + id->root_id->misc->gtext_mi++; + #else +  string sn = "gtext" + id->root_id->misc->gtext_mi++; + #endif +  RXML_CONTEXT->set_root_id_misc("gtext_mi", id->root_id->misc->gtext_mi);    -  string sn = "gtext" + id->misc->gtext_mi++; -  if(!id->supports->js_image_object) { +  if(honor_supports && !id->supports->js_image_object) {    return (!input)?    ("<a"+ea+"href=\""+url+"\">"+Roxen.make_tag("img",arg+(["name":sn]),xml)+"</a>"):    Roxen.make_tag("input",arg+(["type":"image"]),xml);    }       arg->name=sn; -  string res="<script>\n"; -  if(!id->misc->gtext_magic_java) { -  res += "function gtext_mo(ri,hi,txt)\n" -  "{\n" -  " document.images[ri].src = hi.src;\n" -  " if( txt != 0 )\n" -  " setTimeout(\"top.window.status = '\"+txt+\"'\", 100);\n" -  "}"; -  } -  id->misc->gtext_magic_java="yes"; +  string res="<script type='text/javascript'>\n"; +  res += gtext_javascript(id);       return    res+