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
gr_start_logging(GR_MAYBE_UNUSED gr_face * face,const char * log_path)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
graphite_start_logging(FILE *,GrLogMask)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
gr_stop_logging(GR_MAYBE_UNUSED gr_face * face)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
graphite_stop_logging()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
operator <<(json & j,const telemetry & t)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
operator <<(json & j,const telemetry &)161 json & graphite2::operator << (json & j, const telemetry &) throw()
162 {
163 return j;
164 }
165 #endif
166
167
operator <<(json & j,const CharInfo & ci)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
operator <<(json & j,const dslot & ds)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
objectid(const dslot & ds)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
objectid(const Segment * const p)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
268