|
fltk 1.3.0rc3
About: FLTK (Fast Light Tool Kit) is a cross-platform C++ GUI toolkit for UNIX/Linux (X11), Microsoft Windows, and MacOS X. Release candidate.
SfR Fresh Dox: fltk-1.3.0rc3-source.tar.gz ("inofficial" and yet experimental doxygen-generated source code documentation) ![]() |
00001 // 00002 // "$Id: fl_font_mac.cxx 8126 2010-12-28 12:02:23Z manolo $" 00003 // 00004 // MacOS font selection routines for the Fast Light Tool Kit (FLTK). 00005 // 00006 // Copyright 1998-2010 by Bill Spitzak and others. 00007 // 00008 // This library is free software; you can redistribute it and/or 00009 // modify it under the terms of the GNU Library General Public 00010 // License as published by the Free Software Foundation; either 00011 // version 2 of the License, or (at your option) any later version. 00012 // 00013 // This library is distributed in the hope that it will be useful, 00014 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00016 // Library General Public License for more details. 00017 // 00018 // You should have received a copy of the GNU Library General Public 00019 // License along with this library; if not, write to the Free Software 00020 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 00021 // USA. 00022 // 00023 // Please report all bugs and problems on the following page: 00024 // 00025 // http://www.fltk.org/str.php 00026 // 00027 00028 #include <config.h> 00029 00030 /* from fl_utf.c */ 00031 extern unsigned fl_utf8toUtf16(const char* src, unsigned srclen, unsigned short* dst, unsigned dstlen); 00032 00033 // if no font has been selected yet by the user, get one. 00034 #define check_default_font() {if (!fl_fontsize) fl_font(0, 12);} 00035 00036 static const CGAffineTransform font_mx = { 1, 0, 0, -1, 0, 0 }; 00037 00038 Fl_Font_Descriptor::Fl_Font_Descriptor(const char* name, Fl_Fontsize Size) { 00039 next = 0; 00040 # if HAVE_GL 00041 listbase = 0; 00042 # endif 00043 00044 // knowWidths = 0; 00045 // OpenGL needs those for its font handling 00046 q_name = strdup(name); 00047 size = Size; 00048 minsize = maxsize = Size; 00049 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5 00050 if(fl_mac_os_version == 0) fl_open_display(); 00051 if(fl_mac_os_version >= 0x1050) {//unfortunately, CTFontCreateWithName != NULL on 10.4 also! 00052 CFStringRef str = CFStringCreateWithCString(NULL, name, kCFStringEncodingUTF8); 00053 fontref = CTFontCreateWithName(str, size, NULL); 00054 CGGlyph glyph[2]; 00055 const UniChar A[2]={'W','.'}; 00056 CTFontGetGlyphsForCharacters(fontref, A, glyph, 2); 00057 CGSize advances[2]; 00058 double w; 00059 CTFontGetAdvancesForGlyphs(fontref, kCTFontHorizontalOrientation, glyph, advances, 2); 00060 w = advances[0].width; 00061 if( abs(advances[0].width - advances[1].width) < 1E-2 ) {//this is a fixed-width font 00062 //slightly rescale fixed-width fonts so the character width has an integral value 00063 CFRelease(fontref); 00064 CGFloat fsize = size / ( w/floor(w + 0.5) ); 00065 fontref = CTFontCreateWithName(str, fsize, NULL); 00066 w = CTFontGetAdvancesForGlyphs(fontref, kCTFontHorizontalOrientation, glyph, NULL, 1); 00067 } 00068 CFRelease(str); 00069 ascent = (short)(CTFontGetAscent(fontref) + 0.5); 00070 descent = (short)(CTFontGetDescent(fontref) + 0.5); 00071 q_width = w + 0.5; 00072 } 00073 else { 00074 #endif 00075 #if ! __LP64__ 00076 OSStatus err; 00077 // fill our structure with a few default values 00078 ascent = Size*3/4; 00079 descent = Size-ascent; 00080 q_width = Size*2/3; 00081 // now use ATS to get the actual Glyph size information 00082 // say that our passed-in name is encoded as UTF-8, since this works for plain ASCII names too... 00083 CFStringRef cfname = CFStringCreateWithCString(0L, name, kCFStringEncodingUTF8); 00084 ATSFontRef font = ATSFontFindFromName(cfname, kATSOptionFlagsDefault); 00085 if (font) { 00086 ATSFontMetrics m = { 0 }; 00087 ATSFontGetHorizontalMetrics(font, kATSOptionFlagsDefault, &m); 00088 if (m.avgAdvanceWidth) q_width = int(m.avgAdvanceWidth*Size); 00089 // playing with the offsets a little to make standard sizes fit 00090 if (m.ascent) ascent = int(m.ascent*Size-0.5f); 00091 if (m.descent) descent = -int(m.descent*Size-1.5f); 00092 } 00093 CFRelease(cfname); 00094 // now we allocate everything needed to render text in this font later 00095 // get us the default layout and style 00096 err = ATSUCreateTextLayout(&layout); 00097 UniChar mTxt[2] = { 65, 0 }; 00098 err = ATSUSetTextPointerLocation(layout, mTxt, kATSUFromTextBeginning, 1, 1); 00099 err = ATSUCreateStyle(&style); 00100 err = ATSUSetRunStyle(layout, style, kATSUFromTextBeginning, kATSUToTextEnd); 00101 // now set the actual font, size and attributes. We also set the font matrix to 00102 // render our font up-side-down, so when rendered through our inverted CGContext, 00103 // text will appear normal again. 00104 Fixed fsize = IntToFixed(Size); 00105 // ATSUFontID fontID = FMGetFontFromATSFontRef(font); 00106 ATSUFontID fontID; 00107 ATSUFindFontFromName(name, strlen(name), kFontFullName, kFontMacintoshPlatform, kFontRomanScript, kFontEnglishLanguage, &fontID); 00108 00109 // draw the font upside-down... Compensate for fltk/OSX origin differences 00110 static CGAffineTransform font_mx = { 1, 0, 0, -1, 0, 0 }; 00111 ATSUAttributeTag sTag[] = { kATSUFontTag, kATSUSizeTag, kATSUFontMatrixTag }; 00112 ByteCount sBytes[] = { sizeof(ATSUFontID), sizeof(Fixed), sizeof(CGAffineTransform) }; 00113 ATSUAttributeValuePtr sAttr[] = { &fontID, &fsize, &font_mx }; 00114 err = ATSUSetAttributes(style, 3, sTag, sBytes, sAttr); 00115 // next, make sure that Quartz will only render at integer coordinates 00116 ATSLineLayoutOptions llo = kATSLineUseDeviceMetrics | kATSLineDisableAllLayoutOperations; 00117 ATSUAttributeTag aTag[] = { kATSULineLayoutOptionsTag }; 00118 ByteCount aBytes[] = { sizeof(ATSLineLayoutOptions) }; 00119 ATSUAttributeValuePtr aAttr[] = { &llo }; 00120 err = ATSUSetLineControls (layout, kATSUFromTextBeginning, 1, aTag, aBytes, aAttr); 00121 // now we are finally ready to measure some letter to get the bounding box 00122 Fixed bBefore, bAfter, bAscent, bDescent; 00123 err = ATSUGetUnjustifiedBounds(layout, kATSUFromTextBeginning, 1, &bBefore, &bAfter, &bAscent, &bDescent); 00124 // Requesting a certain height font on Mac does not guarantee that ascent+descent 00125 // equal the requested height. fl_height will reflect the actual height that we got. 00126 // The font "Apple Chancery" is a pretty extreme example of overlapping letters. 00127 float fa = -FixedToFloat(bAscent), fd = -FixedToFloat(bDescent); 00128 if (fa>0.0f && fd>0.0f) { 00129 //float f = Size/(fa+fd); 00130 ascent = int(fa); //int(fa*f+0.5f); 00131 descent = int(fd); //Size - ascent; 00132 } 00133 int w = FixedToInt(bAfter); 00134 if (w) 00135 q_width = FixedToInt(bAfter); 00136 00137 # define ENABLE_TRANSIENT_FONTS 1 00138 00139 # ifdef ENABLE_TRANSIENT_FONTS 00140 // Now, by way of experiment, try enabling Transient Font Matching, this will 00141 // cause ATSU to find a suitable font to render any chars the current font can't do... 00142 ATSUSetTransientFontMatching (layout, true); 00143 # endif 00144 #endif//__LP64__ 00145 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5 00146 } 00147 #endif 00148 } 00149 00150 Fl_Font_Descriptor* fl_fontsize = 0L; 00151 00152 Fl_Font_Descriptor::~Fl_Font_Descriptor() { 00153 /* 00154 #if HAVE_GL 00155 // ++ todo: remove OpenGL font alocations 00156 // Delete list created by gl_draw(). This is not done by this code 00157 // as it will link in GL unnecessarily. There should be some kind 00158 // of "free" routine pointer, or a subclass? 00159 // if (listbase) { 00160 // int base = font->min_char_or_byte2; 00161 // int size = font->max_char_or_byte2-base+1; 00162 // int base = 0; int size = 256; 00163 // glDeleteLists(listbase+base,size); 00164 // } 00165 #endif 00166 */ 00167 if (this == fl_fontsize) fl_fontsize = 0; 00168 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5 00169 if(fl_mac_os_version >= 0x1050) CFRelease(fontref); 00170 #else 00171 /* ATSUDisposeTextLayout(layout); 00172 ATSUDisposeStyle(style); */ 00173 #endif 00174 } 00175 00177 00178 static Fl_Fontdesc built_in_table[] = { 00179 {"Arial"}, 00180 {"Arial Bold"}, 00181 {"Arial Italic"}, 00182 {"Arial Bold Italic"}, 00183 {"Courier New"}, 00184 {"Courier New Bold"}, 00185 {"Courier New Italic"}, 00186 {"Courier New Bold Italic"}, 00187 {"Times New Roman"}, 00188 {"Times New Roman Bold"}, 00189 {"Times New Roman Italic"}, 00190 {"Times New Roman Bold Italic"}, 00191 {"Symbol"}, 00192 {"Monaco"}, 00193 {"Andale Mono"}, // there is no bold Monaco font on standard Mac 00194 {"Webdings"}, 00195 }; 00196 00197 static UniChar *utfWbuf = 0; 00198 static unsigned utfWlen = 0; 00199 00200 static UniChar *mac_Utf8_to_Utf16(const char *txt, int len, int *new_len) 00201 { 00202 unsigned wlen = fl_utf8toUtf16(txt, len, (unsigned short*)utfWbuf, utfWlen); 00203 if(wlen >= utfWlen) 00204 { 00205 utfWlen = wlen + 100; 00206 if(utfWbuf) free(utfWbuf); 00207 utfWbuf = (UniChar*)malloc((utfWlen)*sizeof(UniChar)); 00208 wlen = fl_utf8toUtf16(txt, len, (unsigned short*)utfWbuf, utfWlen); 00209 } 00210 *new_len = wlen; 00211 return utfWbuf; 00212 } // mac_Utf8_to_Utf16 00213 00214 Fl_Fontdesc* fl_fonts = built_in_table; 00215 00216 void fl_font(Fl_Font_Descriptor* s) { 00217 fl_fontsize = s; 00218 // we will use fl_fontsize later to access the required style and layout 00219 } 00220 00221 static Fl_Font_Descriptor* find(Fl_Font fnum, Fl_Fontsize size) { 00222 Fl_Fontdesc* s = fl_fonts+fnum; 00223 if (!s->name) s = fl_fonts; // use 0 if fnum undefined 00224 Fl_Font_Descriptor* f; 00225 for (f = s->first; f; f = f->next) 00226 if (f->minsize <= size && f->maxsize >= size) return f; 00227 f = new Fl_Font_Descriptor(s->name, size); 00228 f->next = s->first; 00229 s->first = f; 00230 return f; 00231 } 00232 00234 // Public interface: 00235 00236 Fl_Font fl_font_ = 0; 00237 Fl_Fontsize fl_size_ = 0; 00238 00239 00240 void Fl_Quartz_Graphics_Driver::font(Fl_Font fnum, Fl_Fontsize size) { 00241 if (fnum==-1) { 00242 fl_font_ = 0; 00243 fl_size_ = 0; 00244 return; 00245 } 00246 fl_font_ = fnum; 00247 fl_size_ = size; 00248 fl_font(find(fnum, size)); 00249 } 00250 00251 int fl_height() { 00252 check_default_font(); 00253 if (fl_fontsize) return fl_fontsize->ascent+fl_fontsize->descent; 00254 else return -1; 00255 } 00256 00257 int fl_descent() { 00258 check_default_font(); 00259 if (fl_fontsize) 00260 return fl_fontsize->descent+1; 00261 else return -1; 00262 } 00263 00264 double fl_width(const UniChar* txt, int n) { 00265 check_default_font(); 00266 if (!fl_fontsize) { 00267 check_default_font(); // avoid a crash! 00268 if (!fl_fontsize) 00269 return 8*n; // user must select a font first! 00270 } 00271 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5 00272 if(fl_mac_os_version >= 0x1050) { 00273 CTFontRef fontref = fl_fontsize->fontref; 00274 CFStringRef str = CFStringCreateWithBytes(NULL, (const UInt8*)txt, n * sizeof(UniChar), kCFStringEncodingUTF16, false); 00275 CFAttributedStringRef astr = CFAttributedStringCreate(NULL, str, NULL); 00276 CFMutableAttributedStringRef mastr = CFAttributedStringCreateMutableCopy(NULL, 0, astr); 00277 CFRelease(astr); 00278 CFAttributedStringSetAttribute(mastr, CFRangeMake(0, CFStringGetLength(str)), kCTFontAttributeName, fontref); 00279 CFRelease(str); 00280 CTLineRef ctline = CTLineCreateWithAttributedString(mastr); 00281 CFRelease(mastr); 00282 double retval = CTLineGetTypographicBounds(ctline, NULL, NULL, NULL); 00283 CFRelease(ctline); 00284 return retval; 00285 } 00286 else { 00287 #endif 00288 #if ! __LP64__ 00289 OSStatus err; 00290 Fixed bBefore, bAfter, bAscent, bDescent; 00291 ATSUTextLayout layout; 00292 ByteCount iSize; 00293 ATSUAttributeTag iTag; 00294 ATSUAttributeValuePtr iValuePtr; 00295 00296 // Here's my ATSU text measuring attempt... This seems to do the Right Thing 00297 // now collect our ATSU resources and measure our text string 00298 layout = fl_fontsize->layout; 00299 // activate the current GC 00300 iSize = sizeof(CGContextRef); 00301 iTag = kATSUCGContextTag; 00302 iValuePtr = &fl_gc; 00303 ATSUSetLayoutControls(layout, 1, &iTag, &iSize, &iValuePtr); 00304 // now measure the bounding box 00305 err = ATSUSetTextPointerLocation(layout, txt, kATSUFromTextBeginning, n, n); 00306 err = ATSUGetUnjustifiedBounds(layout, kATSUFromTextBeginning, n, &bBefore, &bAfter, &bAscent, &bDescent); 00307 // If err is OK then return length, else return 0. Or something... 00308 int len = FixedToInt(bAfter); 00309 return len; 00310 #endif 00311 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5 00312 } 00313 #endif 00314 return 0; // FIXME: I do not understand the shuffeling of the above ifdef's and why they are here! 00315 } 00316 00317 double fl_width(const char* txt, int n) { 00318 int wc_len = n; 00319 UniChar *uniStr = mac_Utf8_to_Utf16(txt, n, &wc_len); 00320 return fl_width(uniStr, wc_len); 00321 } 00322 00323 double fl_width(uchar c) { 00324 return fl_width((const char*)(&c), 1); 00325 } 00326 00327 double fl_width(unsigned int wc) { 00328 return fl_width((const UniChar*)(&wc), 1); 00329 } 00330 00331 // text extent calculation 00332 void fl_text_extents(const UniChar* txt, int n, int &dx, int &dy, int &w, int &h) { 00333 if (!fl_fontsize) { 00334 check_default_font(); // avoid a crash! 00335 if (!fl_fontsize) 00336 w = int(8.0 * n); // user must select a font first! 00337 h = int(8.0); 00338 return; 00339 } 00340 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5 00341 if(fl_mac_os_version >= 0x1050) { 00342 CTFontRef fontref = fl_fontsize->fontref; 00343 CFStringRef str16 = CFStringCreateWithBytes(NULL, (const UInt8*)txt, n *sizeof(UniChar), kCFStringEncodingUTF16, false); 00344 CFAttributedStringRef astr = CFAttributedStringCreate(NULL, str16, NULL); 00345 CFMutableAttributedStringRef mastr = CFAttributedStringCreateMutableCopy(NULL, 0, astr); 00346 CFRelease(astr); 00347 CFAttributedStringSetAttribute(mastr, CFRangeMake(0, CFStringGetLength(str16)), kCTFontAttributeName, fontref); 00348 CFRelease(str16); 00349 CTLineRef ctline = CTLineCreateWithAttributedString(mastr); 00350 CFRelease(mastr); 00351 CGContextSetTextPosition(fl_gc, 0, 0); 00352 CGContextSetShouldAntialias(fl_gc, true); 00353 CGRect rect = CTLineGetImageBounds(ctline, fl_gc); 00354 CGContextSetShouldAntialias(fl_gc, false); 00355 CFRelease(ctline); 00356 dx = floor(rect.origin.x + 0.5); 00357 dy = floor(- rect.origin.y - rect.size.height + 0.5); 00358 w = rect.size.width + 0.5; 00359 h = rect.size.height + 0.5; 00360 } 00361 else { 00362 #endif 00363 #if ! __LP64__ 00364 OSStatus err; 00365 ATSUTextLayout layout; 00366 ByteCount iSize; 00367 ATSUAttributeTag iTag; 00368 ATSUAttributeValuePtr iValuePtr; 00369 00370 // Here's my ATSU text measuring attempt... This seems to do the Right Thing 00371 // now collect our ATSU resources and measure our text string 00372 layout = fl_fontsize->layout; 00373 // activate the current GC 00374 iSize = sizeof(CGContextRef); 00375 iTag = kATSUCGContextTag; 00376 iValuePtr = &fl_gc; 00377 ATSUSetLayoutControls(layout, 1, &iTag, &iSize, &iValuePtr); 00378 // now measure the bounding box 00379 err = ATSUSetTextPointerLocation(layout, txt, kATSUFromTextBeginning, n, n); 00380 Rect bbox; 00381 err = ATSUMeasureTextImage(layout, kATSUFromTextBeginning, n, 0, 0, &bbox); 00382 w = bbox.right - bbox.left; 00383 h = bbox.bottom - bbox.top; 00384 dx = bbox.left; 00385 dy = -bbox.bottom; 00386 //printf("r: %d l: %d t: %d b: %d w: %d h: %d\n", bbox.right, bbox.left, bbox.top, bbox.bottom, w, h); 00387 #endif 00388 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5 00389 } 00390 #endif 00391 return; 00392 } // fl_text_extents 00393 00394 void fl_text_extents(const char *c, int n, int &dx, int &dy, int &w, int &h) { 00395 int wc_len = n; 00396 UniChar *uniStr = mac_Utf8_to_Utf16(c, n, &wc_len); 00397 fl_text_extents(uniStr, wc_len, dx, dy, w, h); 00398 } // fl_text_extents 00399 00400 00401 void fl_draw(const char *str, int n, float x, float y); 00402 00403 void Fl_Quartz_Graphics_Driver::draw(const char* str, int n, int x, int y) { 00404 fl_draw(str, n, (float)x-0.0f, (float)y+0.5f); 00405 } 00406 00407 00408 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5 00409 static CGColorRef flcolortocgcolor(Fl_Color i) 00410 { 00411 uchar r, g, b; 00412 Fl::get_color(i, r, g, b); 00413 CGFloat components[4] = {r/255.0f, g/255.0f, b/255.0f, 1.}; 00414 static CGColorSpaceRef cspace = NULL; 00415 if(cspace == NULL) { 00416 cspace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB); 00417 } 00418 return CGColorCreate(cspace, components); 00419 } 00420 #endif 00421 00422 00423 void fl_draw(const char *str, int n, float x, float y) { 00424 // avoid a crash if no font has been selected by user yet ! 00425 check_default_font(); 00426 // convert to UTF-16 first 00427 UniChar *uniStr = mac_Utf8_to_Utf16(str, n, &n); 00428 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5 00429 if(fl_mac_os_version >= 0x1050) { 00430 CFStringRef keys[2]; 00431 CFTypeRef values[2]; 00432 CFStringRef str16 = CFStringCreateWithBytes(NULL, (const UInt8*)uniStr, n * sizeof(UniChar), kCFStringEncodingUTF16, false); 00433 CGColorRef color = flcolortocgcolor(fl_color()); 00434 keys[0] = kCTFontAttributeName; 00435 keys[1] = kCTForegroundColorAttributeName; 00436 values[0] = fl_fontsize->fontref; 00437 values[1] = color; 00438 CFDictionaryRef attributes = CFDictionaryCreate(kCFAllocatorDefault, 00439 (const void**)&keys, 00440 (const void**)&values, 00441 2, 00442 &kCFTypeDictionaryKeyCallBacks, 00443 &kCFTypeDictionaryValueCallBacks); 00444 CFAttributedStringRef mastr = CFAttributedStringCreate(kCFAllocatorDefault, str16, attributes); 00445 CFRelease(str16); 00446 CFRelease(attributes); 00447 CFRelease(color); 00448 CTLineRef ctline = CTLineCreateWithAttributedString(mastr); 00449 CFRelease(mastr); 00450 CGContextSetTextMatrix(fl_gc, font_mx); 00451 CGContextSetTextPosition(fl_gc, x, y); 00452 CGContextSetShouldAntialias(fl_gc, true); 00453 CTLineDraw(ctline, fl_gc); 00454 CGContextSetShouldAntialias(fl_gc, false); 00455 CFRelease(ctline); 00456 } 00457 else { 00458 #endif 00459 #if ! __LP64__ 00460 OSStatus err; 00461 // now collect our ATSU resources 00462 ATSUTextLayout layout = fl_fontsize->layout; 00463 00464 ByteCount iSize = sizeof(CGContextRef); 00465 ATSUAttributeTag iTag = kATSUCGContextTag; 00466 ATSUAttributeValuePtr iValuePtr=&fl_gc; 00467 ATSUSetLayoutControls(layout, 1, &iTag, &iSize, &iValuePtr); 00468 00469 err = ATSUSetTextPointerLocation(layout, uniStr, kATSUFromTextBeginning, n, n); 00470 CGContextSetShouldAntialias(fl_gc, true); 00471 err = ATSUDrawText(layout, kATSUFromTextBeginning, n, FloatToFixed(x), FloatToFixed(y)); 00472 CGContextSetShouldAntialias(fl_gc, false); 00473 #endif 00474 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5 00475 } 00476 #endif 00477 } 00478 00479 void Fl_Quartz_Graphics_Driver::draw(int angle, const char *str, int n, int x, int y) { 00480 CGContextSaveGState(fl_gc); 00481 CGContextTranslateCTM(fl_gc, x, y); 00482 CGContextRotateCTM(fl_gc, - angle*(M_PI/180) ); 00483 fl_draw(str, n, (float)0., (float)0.); 00484 CGContextRestoreGState(fl_gc); 00485 } 00486 00487 void Fl_Quartz_Graphics_Driver::rtl_draw(const char* c, int n, int x, int y) { 00488 draw(c, n, int(x - fl_width(c, n)), y); 00489 } 00490 00491 // 00492 // End of "$Id: fl_font_mac.cxx 8126 2010-12-28 12:02:23Z manolo $". 00493 //