michael@0: /* GRAPHITE2 LICENSING michael@0: michael@0: Copyright 2010, SIL International michael@0: All rights reserved. michael@0: michael@0: This library is free software; you can redistribute it and/or modify michael@0: it under the terms of the GNU Lesser General Public License as published michael@0: by the Free Software Foundation; either version 2.1 of License, or michael@0: (at your option) any later version. michael@0: michael@0: This program is distributed in the hope that it will be useful, michael@0: but WITHOUT ANY WARRANTY; without even the implied warranty of michael@0: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU michael@0: Lesser General Public License for more details. michael@0: michael@0: You should also have received a copy of the GNU Lesser General Public michael@0: License along with this library in the file named "LICENSE". michael@0: If not, write to the Free Software Foundation, 51 Franklin Street, michael@0: Suite 500, Boston, MA 02110-1335, USA or visit their web page on the michael@0: internet at http://www.fsf.org/licenses/lgpl.html. michael@0: michael@0: Alternatively, the contents of this file may be used under the terms of the michael@0: Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public michael@0: License, as published by the Free Software Foundation, either version 2 michael@0: of the License or (at your option) any later version. michael@0: */ michael@0: #include michael@0: michael@0: #include "graphite2/Log.h" michael@0: #include "inc/debug.h" michael@0: #include "inc/CharInfo.h" michael@0: #include "inc/Slot.h" michael@0: #include "inc/Segment.h" michael@0: #include "inc/json.h" michael@0: michael@0: #if defined _WIN32 michael@0: #include "windows.h" michael@0: #endif michael@0: michael@0: using namespace graphite2; michael@0: michael@0: #if !defined GRAPHITE2_NTRACING michael@0: json *global_log = NULL; michael@0: #endif michael@0: michael@0: extern "C" { michael@0: michael@0: bool gr_start_logging(GR_MAYBE_UNUSED gr_face * face, const char *log_path) michael@0: { michael@0: if (!log_path) return false; michael@0: michael@0: #if !defined GRAPHITE2_NTRACING michael@0: gr_stop_logging(face); michael@0: #if defined _WIN32 michael@0: int n = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, log_path, -1, 0, 0); michael@0: if (n == 0 || n > MAX_PATH - 12) return false; michael@0: michael@0: LPWSTR wlog_path = gralloc(n); michael@0: if (!wlog_path) return false; michael@0: FILE *log = 0; michael@0: if (wlog_path && MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, log_path, -1, wlog_path, n)) michael@0: log = _wfopen(wlog_path, L"wt"); michael@0: michael@0: free(wlog_path); michael@0: #else // _WIN32 michael@0: FILE *log = fopen(log_path, "wt"); michael@0: #endif // _WIN32 michael@0: if (!log) return false; michael@0: michael@0: if (face) michael@0: { michael@0: face->setLogger(log); michael@0: if (!face->logger()) return false; michael@0: michael@0: *face->logger() << json::array; michael@0: #ifdef GRAPHITE2_TELEMETRY michael@0: *face->logger() << face->tele; michael@0: #endif michael@0: } michael@0: else michael@0: { michael@0: global_log = new json(log); michael@0: *global_log << json::array; michael@0: } michael@0: michael@0: return true; michael@0: #else // GRAPHITE2_NTRACING michael@0: return false; michael@0: #endif // GRAPHITE2_NTRACING michael@0: } michael@0: michael@0: bool graphite_start_logging(FILE * /* log */, GrLogMask /* mask */) michael@0: { michael@0: //#if !defined GRAPHITE2_NTRACING michael@0: // graphite_stop_logging(); michael@0: // michael@0: // if (!log) return false; michael@0: // michael@0: // dbgout = new json(log); michael@0: // if (!dbgout) return false; michael@0: // michael@0: // *dbgout << json::array; michael@0: // return true; michael@0: //#else michael@0: return false; michael@0: //#endif michael@0: } michael@0: michael@0: void gr_stop_logging(GR_MAYBE_UNUSED gr_face * face) michael@0: { michael@0: #if !defined GRAPHITE2_NTRACING michael@0: if (face && face->logger()) michael@0: { michael@0: FILE * log = face->logger()->stream(); michael@0: face->setLogger(0); michael@0: fclose(log); michael@0: } michael@0: else if (!face && global_log) michael@0: { michael@0: FILE * log = global_log->stream(); michael@0: delete global_log; michael@0: fclose(log); michael@0: } michael@0: #endif michael@0: } michael@0: michael@0: void graphite_stop_logging() michael@0: { michael@0: // if (dbgout) delete dbgout; michael@0: // dbgout = 0; michael@0: } michael@0: michael@0: } // extern "C" michael@0: michael@0: #ifdef GRAPHITE2_TELEMETRY michael@0: size_t * graphite2::telemetry::_category = 0UL; michael@0: #endif michael@0: michael@0: #if !defined GRAPHITE2_NTRACING michael@0: michael@0: #ifdef GRAPHITE2_TELEMETRY michael@0: michael@0: json & graphite2::operator << (json & j, const telemetry & t) throw() michael@0: { michael@0: j << json::object michael@0: << "type" << "telemetry" michael@0: << "silf" << t.silf michael@0: << "states" << t.states michael@0: << "starts" << t.starts michael@0: << "transitions" << t.transitions michael@0: << "glyphs" << t.glyph michael@0: << "code" << t.code michael@0: << "misc" << t.misc michael@0: << "total" << (t.silf + t.states + t.starts + t.transitions + t.glyph + t.code + t.misc) michael@0: << json::close; michael@0: return j; michael@0: } michael@0: #else michael@0: json & graphite2::operator << (json & j, const telemetry &) throw() michael@0: { michael@0: return j; michael@0: } michael@0: #endif michael@0: michael@0: michael@0: json & graphite2::operator << (json & j, const CharInfo & ci) throw() michael@0: { michael@0: return j << json::object michael@0: << "offset" << ci.base() michael@0: << "unicode" << ci.unicodeChar() michael@0: << "break" << ci.breakWeight() michael@0: << "flags" << ci.flags() michael@0: << "slot" << json::flat << json::object michael@0: << "before" << ci.before() michael@0: << "after" << ci.after() michael@0: << json::close michael@0: << json::close; michael@0: } michael@0: michael@0: michael@0: json & graphite2::operator << (json & j, const dslot & ds) throw() michael@0: { michael@0: assert(ds.first); michael@0: assert(ds.second); michael@0: const Segment & seg = *ds.first; michael@0: const Slot & s = *ds.second; michael@0: michael@0: j << json::object michael@0: << "id" << objectid(ds) michael@0: << "gid" << s.gid() michael@0: << "charinfo" << json::flat << json::object michael@0: << "original" << s.original() michael@0: << "before" << s.before() michael@0: << "after" << s.after() michael@0: << json::close michael@0: << "origin" << s.origin() michael@0: << "shift" << Position(float(s.getAttr(0, gr_slatShiftX, 0)), michael@0: float(s.getAttr(0, gr_slatShiftY, 0))) michael@0: << "advance" << s.advancePos() michael@0: << "insert" << s.isInsertBefore() michael@0: << "break" << s.getAttr(&seg, gr_slatBreak, 0); michael@0: if (s.just() > 0) michael@0: j << "justification" << s.just(); michael@0: if (s.getBidiLevel() > 0) michael@0: j << "bidi" << s.getBidiLevel(); michael@0: if (!s.isBase()) michael@0: j << "parent" << json::flat << json::object michael@0: << "id" << objectid(dslot(&seg, s.attachedTo())) michael@0: << "level" << s.getAttr(0, gr_slatAttLevel, 0) michael@0: << "offset" << s.attachOffset() michael@0: << json::close; michael@0: j << "user" << json::flat << json::array; michael@0: for (int n = 0; n!= seg.numAttrs(); ++n) michael@0: j << s.userAttrs()[n]; michael@0: j << json::close; michael@0: if (s.firstChild()) michael@0: { michael@0: j << "children" << json::flat << json::array; michael@0: for (const Slot *c = s.firstChild(); c; c = c->nextSibling()) michael@0: j << objectid(dslot(&seg, c)); michael@0: j << json::close; michael@0: } michael@0: return j << json::close; michael@0: } michael@0: michael@0: michael@0: graphite2::objectid::objectid(const dslot & ds) throw() michael@0: { michael@0: const Slot * const p = ds.second; michael@0: uint32 s = reinterpret_cast(p); michael@0: sprintf(name, "%.4x-%.2x-%.4hx", uint16(s >> 16), uint16(p ? p->userAttrs()[ds.first->silf()->numUser()] : 0), uint16(s)); michael@0: name[sizeof name-1] = 0; michael@0: } michael@0: michael@0: graphite2::objectid::objectid(const Segment * const p) throw() michael@0: { michael@0: uint32 s = reinterpret_cast(p); michael@0: sprintf(name, "%.4x-%.2x-%.4hx", uint16(s >> 16), 0, uint16(s)); michael@0: name[sizeof name-1] = 0; michael@0: } michael@0: michael@0: #endif