gr_logging.cpp (8158B)
1 /* GRAPHITE2 LICENSING 2 3 Copyright 2010, SIL International 4 All rights reserved. 5 6 This library is free software; you can redistribute it and/or modify 7 it under the terms of the GNU Lesser General Public License as published 8 by the Free Software Foundation; either version 2.1 of License, or 9 (at your option) any later version. 10 11 This program 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 GNU 14 Lesser General Public License for more details. 15 16 You should also have received a copy of the GNU Lesser General Public 17 License along with this library in the file named "LICENSE". 18 If not, write to the Free Software Foundation, 51 Franklin Street, 19 Suite 500, Boston, MA 02110-1335, USA or visit their web page on the 20 internet at http://www.fsf.org/licenses/lgpl.html. 21 22 Alternatively, the contents of this file may be used under the terms of the 23 Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public 24 License, as published by the Free Software Foundation, either version 2 25 of the License or (at your option) any later version. 26 */ 27 #include <cstdio> 28 29 #include "graphite2/Log.h" 30 #include "inc/debug.h" 31 #include "inc/CharInfo.h" 32 #include "inc/Slot.h" 33 #include "inc/Segment.h" 34 #include "inc/json.h" 35 #include "inc/Collider.h" 36 37 #if defined _WIN32 38 #include "windows.h" 39 #endif 40 41 using namespace graphite2; 42 43 #if !defined GRAPHITE2_NTRACING 44 json *global_log = 0; 45 #endif 46 47 extern "C" { 48 49 bool gr_start_logging(GR_MAYBE_UNUSED gr_face * face, const char *log_path) 50 { 51 if (!log_path) return false; 52 53 #if !defined GRAPHITE2_NTRACING 54 gr_stop_logging(face); 55 #if defined _WIN32 56 int n = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, log_path, -1, 0, 0); 57 if (n == 0 || n > MAX_PATH - 12) return false; 58 59 LPWSTR wlog_path = gralloc<WCHAR>(n); 60 if (!wlog_path) return false; 61 FILE *log = 0; 62 if (wlog_path && MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, log_path, -1, wlog_path, n)) 63 log = _wfopen(wlog_path, L"wt"); 64 65 free(wlog_path); 66 #else // _WIN32 67 FILE *log = fopen(log_path, "wt"); 68 #endif // _WIN32 69 if (!log) return false; 70 71 if (face) 72 { 73 face->setLogger(log); 74 if (!face->logger()) return false; 75 76 *face->logger() << json::array; 77 #ifdef GRAPHITE2_TELEMETRY 78 *face->logger() << face->tele; 79 #endif 80 } 81 else 82 { 83 global_log = new json(log); 84 *global_log << json::array; 85 } 86 87 return true; 88 #else // GRAPHITE2_NTRACING 89 return false; 90 #endif // GRAPHITE2_NTRACING 91 } 92 93 bool graphite_start_logging(FILE * /* log */, GrLogMask /* mask */) 94 { 95 //#if !defined GRAPHITE2_NTRACING 96 // graphite_stop_logging(); 97 // 98 // if (!log) return false; 99 // 100 // dbgout = new json(log); 101 // if (!dbgout) return false; 102 // 103 // *dbgout << json::array; 104 // return true; 105 //#else 106 return false; 107 //#endif 108 } 109 110 void gr_stop_logging(GR_MAYBE_UNUSED gr_face * face) 111 { 112 #if !defined GRAPHITE2_NTRACING 113 if (face && face->logger()) 114 { 115 FILE * log = face->logger()->stream(); 116 face->setLogger(0); 117 fclose(log); 118 } 119 else if (!face && global_log) 120 { 121 FILE * log = global_log->stream(); 122 delete global_log; 123 global_log = 0; 124 fclose(log); 125 } 126 #endif 127 } 128 129 void graphite_stop_logging() 130 { 131 // if (dbgout) delete dbgout; 132 // dbgout = 0; 133 } 134 135 } // extern "C" 136 137 #ifdef GRAPHITE2_TELEMETRY 138 size_t * graphite2::telemetry::_category = 0UL; 139 #endif 140 141 #if !defined GRAPHITE2_NTRACING 142 143 #ifdef GRAPHITE2_TELEMETRY 144 145 json & graphite2::operator << (json & j, const telemetry & t) throw() 146 { 147 j << json::object 148 << "type" << "telemetry" 149 << "silf" << t.silf 150 << "states" << t.states 151 << "starts" << t.starts 152 << "transitions" << t.transitions 153 << "glyphs" << t.glyph 154 << "code" << t.code 155 << "misc" << t.misc 156 << "total" << (t.silf + t.states + t.starts + t.transitions + t.glyph + t.code + t.misc) 157 << json::close; 158 return j; 159 } 160 #else 161 json & graphite2::operator << (json & j, const telemetry &) throw() 162 { 163 return j; 164 } 165 #endif 166 167 168 json & graphite2::operator << (json & j, const CharInfo & ci) throw() 169 { 170 return j << json::object 171 << "offset" << ci.base() 172 << "unicode" << ci.unicodeChar() 173 << "break" << ci.breakWeight() 174 << "flags" << ci.flags() 175 << "slot" << json::flat << json::object 176 << "before" << ci.before() 177 << "after" << ci.after() 178 << json::close 179 << json::close; 180 } 181 182 183 json & graphite2::operator << (json & j, const dslot & ds) throw() 184 { 185 assert(ds.first); 186 assert(ds.second); 187 const Segment & seg = *ds.first; 188 const Slot & s = *ds.second; 189 const SlotCollision *cslot = seg.collisionInfo(ds.second); 190 191 j << json::object 192 << "id" << objectid(ds) 193 << "gid" << s.gid() 194 << "charinfo" << json::flat << json::object 195 << "original" << s.original() 196 << "before" << s.before() 197 << "after" << s.after() 198 << json::close 199 << "origin" << s.origin() 200 << "shift" << Position(float(s.getAttr(0, gr_slatShiftX, 0)), 201 float(s.getAttr(0, gr_slatShiftY, 0))) 202 << "advance" << s.advancePos() 203 << "insert" << s.isInsertBefore() 204 << "break" << s.getAttr(&seg, gr_slatBreak, 0); 205 if (s.just() > 0) 206 j << "justification" << s.just(); 207 if (s.getBidiLevel() > 0) 208 j << "bidi" << s.getBidiLevel(); 209 if (!s.isBase()) 210 j << "parent" << json::flat << json::object 211 << "id" << objectid(dslot(&seg, s.attachedTo())) 212 << "level" << s.getAttr(0, gr_slatAttLevel, 0) 213 << "offset" << s.attachOffset() 214 << json::close; 215 j << "user" << json::flat << json::array; 216 for (int n = 0; n!= seg.numAttrs(); ++n) 217 j << s.userAttrs()[n]; 218 j << json::close; 219 if (s.firstChild()) 220 { 221 j << "children" << json::flat << json::array; 222 for (const Slot *c = s.firstChild(); c; c = c->nextSibling()) 223 j << objectid(dslot(&seg, c)); 224 j << json::close; 225 } 226 if (cslot) 227 { 228 // Note: the reason for using Positions to lump together related attributes is to make the 229 // JSON output slightly more compact. 230 j << "collision" << json::flat << json::object 231 // << "shift" << cslot->shift() -- not used pass level, only within the collision routine itself 232 << "offset" << cslot->offset() 233 << "limit" << cslot->limit() 234 << "flags" << cslot->flags() 235 << "margin" << Position(cslot->margin(), cslot->marginWt()) 236 << "exclude" << cslot->exclGlyph() 237 << "excludeoffset" << cslot->exclOffset(); 238 if (cslot->seqOrder() != 0) 239 { 240 j << "seqclass" << Position(cslot->seqClass(), cslot->seqProxClass()) 241 << "seqorder" << cslot->seqOrder() 242 << "seqabove" << Position(cslot->seqAboveXoff(), cslot->seqAboveWt()) 243 << "seqbelow" << Position(cslot->seqBelowXlim(), cslot->seqBelowWt()) 244 << "seqvalign" << Position(cslot->seqValignHt(), cslot->seqValignWt()); 245 } 246 j << json::close; 247 } 248 return j << json::close; 249 } 250 251 252 graphite2::objectid::objectid(const dslot & ds) throw() 253 { 254 const Slot * const p = ds.second; 255 uint32 s = uint32(reinterpret_cast<size_t>(p)); 256 sprintf(name, "%.4x-%.2x-%.4hx", uint16(s >> 16), uint16(p ? p->userAttrs()[ds.first->silf()->numUser()] : 0), uint16(s)); 257 name[sizeof name-1] = 0; 258 } 259 260 graphite2::objectid::objectid(const Segment * const p) throw() 261 { 262 uint32 s = uint32(reinterpret_cast<size_t>(p)); 263 sprintf(name, "%.4x-%.2x-%.4hx", uint16(s >> 16), 0, uint16(s)); 264 name[sizeof name-1] = 0; 265 } 266 267 #endif