static void utf16_to_utf8(const UChar* aText, gint aLength, char* &text, gint &length) { gboolean need_copy = FALSE; int i; for (i = 0; i < aLength; i++) { if (!aText[i] || IS_LOW_SURROGATE(aText[i])) { need_copy = TRUE; break; } else if (IS_HIGH_SURROGATE(aText[i])) { if (i < aLength - 1 && IS_LOW_SURROGATE(aText[i+1])) i++; else { need_copy = TRUE; break; } } } if (need_copy) { /* Pango doesn't correctly handle nuls. We convert them to 0xff. */ /* Also "validate" UTF-16 text to make sure conversion doesn't fail. */ UChar* p = (UChar*)g_memdup(aText, aLength * sizeof(aText[0])); /* don't need to reset i */ for (i = 0; i < aLength; i++) { if (!p[i] || IS_LOW_SURROGATE(p[i])) p[i] = 0xFFFD; else if (IS_HIGH_SURROGATE(p[i])) { if (i < aLength - 1 && IS_LOW_SURROGATE(aText[i+1])) i++; else p[i] = 0xFFFD; } } aText = p; } glong items_written; text = g_utf16_to_utf8(reinterpret_cast<const gunichar2*>(aText), aLength, NULL, &items_written, NULL); length = items_written; if (need_copy) g_free((gpointer)aText); }
static void utf16ToUcs4(const nsAString& in, PRUint32 *out, PRUint32 outBufLen, PRUint32 *outLen) { PRUint32 i = 0; nsAString::const_iterator start, end; in.BeginReading(start); in.EndReading(end); while (start != end) { PRUnichar curChar; curChar= *start++; if (start != end && IS_HIGH_SURROGATE(curChar) && IS_LOW_SURROGATE(*start)) { out[i] = SURROGATE_TO_UCS4(curChar, *start); ++start; } else out[i] = curChar; i++; if (i >= outBufLen) { NS_ERROR("input too big, the result truncated"); out[outBufLen-1] = (PRUint32)'\0'; *outLen = i; return; } } out[i] = (PRUint32)'\0'; *outLen = i; }
NS_IMETHODIMP nsEntityConverter::ConvertToEntities(const PRUnichar *inString, PRUint32 entityVersion, PRUnichar **_retval) { NS_ASSERTION(inString, "null ptr- inString"); NS_ASSERTION(_retval, "null ptr- _retval"); if((nsnull == inString) || (nsnull == _retval)) return NS_ERROR_NULL_POINTER; *_retval = NULL; const PRUnichar *entity = NULL; nsString outString; // per character look for the entity PRUint32 len = nsCRT::strlen(inString); for (PRUint32 i = 0; i < len; i++) { nsAutoString key(NS_LITERAL_STRING("entity.")); if (IS_HIGH_SURROGATE(inString[i]) && i + 2 < len && IS_LOW_SURROGATE(inString[i + 1])) { key.AppendInt(SURROGATE_TO_UCS4(inString[i], inString[++i]), 10); } else { key.AppendInt(inString[i],10); } nsXPIDLString value; entity = NULL; for (PRUint32 mask = 1, mask2 = 0xFFFFFFFFL; (0!=(entityVersion & mask2)); mask<<=1, mask2<<=1) { if (0 == (entityVersion & mask)) continue; nsIStringBundle* entities = GetVersionBundleInstance(entityVersion & mask); NS_ASSERTION(entities, "Cannot get the property file"); if (NULL == entities) continue; nsresult rv = entities->GetStringFromName(key.get(), getter_Copies(value)); if (NS_SUCCEEDED(rv)) { entity = value.get(); break; } } if (NULL != entity) { outString.Append(entity); } else { outString.Append(&inString[i], 1); } } *_retval = ToNewUnicode(outString); if (NULL == *_retval) return NS_ERROR_OUT_OF_MEMORY; return NS_OK; }
gint nsFreeTypeFont::GetWidth(const PRUnichar* aString, PRUint32 aLength) { FT_UInt glyph_index; FT_Glyph glyph; FT_Pos origin_x = 0; // get the face/size from the FreeType cache FT_Face face = getFTFace(); NS_ASSERTION(face, "failed to get face/size"); if (!face) return 0; FTC_Image_Cache icache; mFt2->GetImageCache(&icache); if (!icache) return 0; PRUint32 i, extraSurrogateLength; for (i=0; i<aLength; i+=1+extraSurrogateLength) { extraSurrogateLength=0; FT_ULong code_point = aString[i]; if(i<aLength-1 && IS_HIGH_SURROGATE(code_point) && IS_LOW_SURROGATE(aString[i+1])) { // if surrogate, make UCS4 code point from high aString[i] surrogate and // low surrogate aString[i+1] code_point = SURROGATE_TO_UCS4(code_point, aString[i+1]); // skip aString[i+1], it is already used as low surrogate extraSurrogateLength = 1; } mFt2->GetCharIndex((FT_Face)face, code_point, &glyph_index); nsresult rv; rv = mFt2->ImageCacheLookup(icache, &mImageDesc, glyph_index, &glyph); NS_ASSERTION(NS_SUCCEEDED(rv),"error loading glyph"); if (NS_FAILED(rv)) { origin_x += face->size->metrics.x_ppem/2 + 2; continue; } origin_x += FT_16_16_TO_REG(glyph->advance.x); } return origin_x; }
gint nsFreeTypeXImage::DrawString(nsRenderingContextGTK* aContext, nsDrawingSurfaceGTK* aSurface, nscoord aX, nscoord aY, const PRUnichar* aString, PRUint32 aLength) { #if DEBUG_SHOW_GLYPH_BOX PRUint32 x, y; // grey shows image size // red shows character cells // green box shows text ink #endif if (aLength < 1) { return 0; } // get the face/size from the FreeType cache FT_Face face = getFTFace(); NS_ASSERTION(face, "failed to get face/size"); if (!face) return 0; nsresult rslt; PRInt32 leftBearing, rightBearing, ascent, descent, width; rslt = doGetBoundingMetrics(aString, aLength, &leftBearing, &rightBearing, &ascent, &descent, &width); if (NS_FAILED(rslt)) return 0; // make sure we bring down enough background for blending rightBearing = PR_MAX(rightBearing, width+1); // offset in the ximage to the x origin PRInt32 x_origin = PR_MAX(0, -leftBearing); // offset in the ximage to the x origin PRInt32 y_origin = ascent; PRInt32 x_pos = x_origin; int image_width = x_origin + rightBearing; int image_height = y_origin + PR_MAX(descent, 0); if ((image_width<=0) || (image_height<=0)) { // if we do not have any pixels then no point in trying to draw // eg: the space char has 0 height NS_ASSERTION(width>=0, "Negative width"); return width; } Display *dpy = GDK_DISPLAY(); Drawable win = GDK_WINDOW_XWINDOW(aSurface->GetDrawable()); GC gc = GDK_GC_XGC(aContext->GetGC()); XGCValues values; if (!XGetGCValues(dpy, gc, GCForeground, &values)) { NS_ERROR("failed to get foreground pixel"); return 0; } nscolor color = nsX11AlphaBlend::PixelToNSColor(values.foreground); #if DEBUG_SHOW_GLYPH_BOX // show X/Y origin XDrawLine(dpy, win, DefaultGC(dpy, 0), aX-2, aY, aX+2, aY); XDrawLine(dpy, win, DefaultGC(dpy, 0), aX, aY-2, aX, aY+2); // show width XDrawLine(dpy, win, DefaultGC(dpy, 0), aX-x_origin, aY-y_origin-2, aX+rightBearing, aY-y_origin-2); #endif // // Get the background // XImage *sub_image = nsX11AlphaBlend::GetBackground(dpy, DefaultScreen(dpy), win, aX-x_origin, aY-y_origin, image_width, image_height); if (sub_image==nsnull) { #ifdef DEBUG int screen = DefaultScreen(dpy); // complain if the requested area is not completely off screen int win_width = DisplayWidth(dpy, screen); int win_height = DisplayHeight(dpy, screen); if (((int)(aX-leftBearing+image_width) > 0) // not hidden to left && ((int)(aX-leftBearing) < win_width) // not hidden to right && ((int)(aY-ascent+image_height) > 0)// not hidden to top && ((int)(aY-ascent) < win_height)) // not hidden to bottom { NS_ASSERTION(sub_image, "failed to get the image"); } #endif return 0; } #if DEBUG_SHOW_GLYPH_BOX DEBUG_AADRAWBOX(sub_image,0,0,image_width,image_height,0,0,0,255/4); nscolor black NS_RGB(0,255,0); blendPixel blendPixelFunc = nsX11AlphaBlend::GetBlendPixel(); // x origin for (x=0; x<(unsigned int)image_height; x++) if (x%4==0) (*blendPixelFunc)(sub_image, x_origin, x, black, 255/2); // y origin for (y=0; y<(unsigned int)image_width; y++) if (y%4==0) (*blendPixelFunc)(sub_image, y, ascent-1, black, 255/2); #endif FTC_Image_Cache icache; mFt2->GetImageCache(&icache); if (!icache) return 0; // // Get aa glyphs and blend with background // blendGlyph blendGlyph = nsX11AlphaBlend::GetBlendGlyph(); PRUint32 i, extraSurrogateLength; for (i=0; i<aLength; i+=1+extraSurrogateLength) { FT_UInt glyph_index; FT_Glyph glyph; nsresult rv; FT_BBox glyph_bbox; FT_ULong code_point = aString[i]; extraSurrogateLength = 0; if(i<aLength-1 && IS_HIGH_SURROGATE(code_point) && IS_LOW_SURROGATE(aString[i+1])) { // if surrogate, make UCS4 code point from high aString[i] surrogate and // low surrogate aString[i+1] code_point = SURROGATE_TO_UCS4(code_point, aString[i+1]); // skip aString[i+1], it is already used as low surrogate extraSurrogateLength = 1; } mFt2->GetCharIndex(face, code_point, &glyph_index); if (glyph_index) { rv = mFt2->ImageCacheLookup(icache, &mImageDesc, glyph_index, &glyph); } if ((glyph_index) && (NS_SUCCEEDED(rv))) { mFt2->GlyphGetCBox(glyph, ft_glyph_bbox_pixels, &glyph_bbox); } else { // draw an empty box for the missing glyphs GetFallbackGlyphMetrics(&glyph_bbox, face); int x, y, w = glyph_bbox.xMax, h = glyph_bbox.yMax; for (x=1; x<w; x++) { XPutPixel(sub_image, x_pos+x, ascent-1, values.foreground); XPutPixel(sub_image, x_pos+x, ascent-h, values.foreground); } for (y=1; y<h; y++) { XPutPixel(sub_image, x_pos+1, ascent-y, values.foreground); XPutPixel(sub_image, x_pos+w-1, ascent-y, values.foreground); x = (y*(w-2))/h; XPutPixel(sub_image, x_pos+x+1, ascent-y, values.foreground); } x_pos += w + 1; continue; } FT_BitmapGlyph slot = (FT_BitmapGlyph)glyph; nsAntiAliasedGlyph aaglyph(glyph_bbox.xMax-glyph_bbox.xMin, glyph_bbox.yMax-glyph_bbox.yMin, 0); PRUint8 buf[IMAGE_BUFFER_SIZE]; // try to use the stack for data if (!aaglyph.WrapFreeType(&glyph_bbox, slot, buf, IMAGE_BUFFER_SIZE)) { NS_ERROR("failed to wrap freetype image"); XDestroyImage(sub_image); return 0; } // // blend the aa-glyph onto the background // NS_ASSERTION(ascent>=glyph_bbox.yMax,"glyph too tall"); NS_ASSERTION(x_pos>=-aaglyph.GetLBearing(),"glyph extends too far to left"); #if DEBUG_SHOW_GLYPH_BOX // draw box around part of glyph that extends to the left // of the main area (negative LBearing) if (aaglyph.GetLBearing() < 0) { DEBUG_AADRAWBOX(sub_image, x_pos + aaglyph.GetLBearing(), ascent-glyph_bbox.yMax, -aaglyph.GetLBearing(), glyph_bbox.yMax, 255,0,0, 255/4); } // draw box around main glyph area DEBUG_AADRAWBOX(sub_image, x_pos, ascent-glyph_bbox.yMax, aaglyph.GetAdvance(), glyph_bbox.yMax, 0,255,0, 255/4); // draw box around part of glyph that extends to the right // of the main area (negative LBearing) if (aaglyph.GetRBearing() > (int)aaglyph.GetAdvance()) { DEBUG_AADRAWBOX(sub_image, x_pos + aaglyph.GetAdvance(), ascent-glyph_bbox.yMax, aaglyph.GetRBearing()-aaglyph.GetAdvance(), glyph_bbox.yMax, 0,0,255, 255/4); } #endif (*blendGlyph)(sub_image, &aaglyph, sLinearWeightTable, color, x_pos + aaglyph.GetLBearing(), ascent-glyph_bbox.yMax); x_pos += aaglyph.GetAdvance(); } // // Send it to the display // XPutImage(dpy, win, gc, sub_image, 0, 0, aX-x_origin , aY-ascent, image_width, image_height); XDestroyImage(sub_image); return width; }
nsresult nsFreeTypeFont::doGetBoundingMetrics(const PRUnichar* aString, PRUint32 aLength, PRInt32* aLeftBearing, PRInt32* aRightBearing, PRInt32* aAscent, PRInt32* aDescent, PRInt32* aWidth) { nsresult rv; *aLeftBearing = 0; *aRightBearing = 0; *aAscent = 0; *aDescent = 0; *aWidth = 0; if (aLength < 1) { return NS_ERROR_FAILURE; } FT_Pos pos = 0; FT_BBox bbox; // initialize to "uninitialized" values bbox.xMin = bbox.yMin = 32000; bbox.xMax = bbox.yMax = -32000; // get the face/size from the FreeType cache FT_Face face = getFTFace(); NS_ASSERTION(face, "failed to get face/size"); if (!face) return NS_ERROR_FAILURE; FTC_Image_Cache icache; mFt2->GetImageCache(&icache); if (!icache) return NS_ERROR_FAILURE; // get the text size PRUint32 i, extraSurrogateLength; for (i=0; i<aLength; i+=1+extraSurrogateLength) { FT_UInt glyph_index; FT_Glyph glyph; FT_BBox glyph_bbox; FT_Pos advance; extraSurrogateLength=0; FT_ULong code_point = aString[i]; if(i<aLength-1 && IS_HIGH_SURROGATE(code_point) && IS_LOW_SURROGATE(aString[i+1])) { // if surrogate, make UCS4 code point from high aString[i] surrogate and // low surrogate aString[i+1] code_point = SURROGATE_TO_UCS4(code_point, aString[i+1]); // skip aString[i+1], it is already used as low surrogate extraSurrogateLength = 1; } mFt2->GetCharIndex(face, code_point, &glyph_index); //NS_ASSERTION(glyph_index,"failed to get glyph"); if (glyph_index) { rv = mFt2->ImageCacheLookup(icache, &mImageDesc, glyph_index, &glyph); NS_ASSERTION(NS_SUCCEEDED(rv),"error loading glyph"); } if ((glyph_index) && (NS_SUCCEEDED(rv))) { mFt2->GlyphGetCBox(glyph, ft_glyph_bbox_pixels, &glyph_bbox); advance = FT_16_16_TO_REG(glyph->advance.x); } else { // allocate space to draw an empty box in GetFallbackGlyphMetrics(&glyph_bbox, face); advance = glyph_bbox.xMax + 1; } bbox.xMin = PR_MIN(pos+glyph_bbox.xMin, bbox.xMin); bbox.xMax = PR_MAX(pos+glyph_bbox.xMax, bbox.xMax); bbox.yMin = PR_MIN(glyph_bbox.yMin, bbox.yMin); bbox.yMax = PR_MAX(glyph_bbox.yMax, bbox.yMax); pos += advance; } // check we got at least one size if (bbox.xMin > bbox.xMax) bbox.xMin = bbox.xMax = bbox.yMin = bbox.yMax = 0; *aLeftBearing = bbox.xMin; *aRightBearing = bbox.xMax; *aAscent = bbox.yMax; *aDescent = -bbox.yMin; *aWidth = pos; return NS_OK; }
DWORD WINAPI MakeNSISProc(LPVOID TreadParam) { TCHAR eventnamebuf[100]; wsprintf(eventnamebuf, MakensisAPI::SigintEventNameFmt, g_sdata.hwnd); if (g_sdata.sigint_event) CloseHandle(g_sdata.sigint_event); g_sdata.sigint_event = CreateEvent(NULL, FALSE, FALSE, eventnamebuf); if (!g_sdata.sigint_event) { ErrorMessage(g_sdata.hwnd, _T("There was an error creating the abort event.")); PostMessage(g_sdata.hwnd, WM_MAKENSIS_PROCESSCOMPLETE, 0, 0); return 1; } STARTUPINFO si; HANDLE newstdout,read_stdout; if (!InitSpawn(si, read_stdout, newstdout)) { ErrorMessage(g_sdata.hwnd, _T("There was an error creating the pipe.")); PostMessage(g_sdata.hwnd, WM_MAKENSIS_PROCESSCOMPLETE, 0, 0); return 1; } PROCESS_INFORMATION pi; if (!CreateProcess(0, g_sdata.compile_command, 0, 0, TRUE, CREATE_NEW_CONSOLE, 0, 0, &si, &pi)) { TCHAR buf[MAX_STRING]; // BUGBUG: TODO: Too small? wsprintf(buf,_T("Could not execute:\r\n %s."), g_sdata.compile_command); ErrorMessage(g_sdata.hwnd, buf); FreeSpawn(0, read_stdout, newstdout); PostMessage(g_sdata.hwnd, WM_MAKENSIS_PROCESSCOMPLETE, 0, 0); return 1; } CloseHandle(newstdout); // close this handle (duplicated in subprocess) now so we get ERROR_BROKEN_PIPE char iob[1024 & ~1]; WCHAR *p = (WCHAR*) iob, wcl = 0, wct = 0; DWORD cb = 0, cbofs = 0, cch, cbio; for(;;) { BOOL rok = ReadFile(read_stdout, iob+cbofs, sizeof(iob)-cbofs, &cbio, NULL); cb += cbio; logappend: cch = cb / sizeof(WCHAR); if (!cch) { if (!rok) break; cbofs += cbio; continue; } bool fullbuf = sizeof(iob) == cb, incompsurr = false; cbofs = 0, cb = 0, --cch; if (fullbuf || (incompsurr = IS_HIGH_SURROGATE(p[cch]))) { wcl = p[cch], cbofs = sizeof(WCHAR); if (cch && IS_HIGH_SURROGATE(p[cch-1]) && !incompsurr) wct = wcl, wcl = p[cch-1], cbofs += sizeof(WCHAR); } p[cch] = L'\0'; LogMessage(g_sdata.hwnd, p); p[0] = wcl, p[1] = wct; if (!rok) { if (cbofs) { if (incompsurr) p[0] = 0xfffd, cbofs = sizeof(WCHAR); // Unable to complete the surrogate pair cb = cbofs; goto logappend; } break; } } FreeSpawn(&pi, read_stdout, 0); g_sdata.retcode = pi.dwProcessId; PostMessage(g_sdata.hwnd, WM_MAKENSIS_PROCESSCOMPLETE, 0, 0); return 0; }
void Client::updateStatus(Json::Value& msg, Ime::EditSession* session) { // We need to handle ordering of some types of the requests. // For example, setCompositionCursor() should happen after setCompositionCursor(). // set sel keys before update candidates const auto& setSelKeysVal = msg["setSelKeys"]; if (setSelKeysVal.isString()) { // keys used to select candidates std::wstring selKeys = utf8ToUtf16(setSelKeysVal.asCString()); textService_->setSelKeys(selKeys); } // show message bool endComposition = false; const auto& showMessageVal = msg["showMessage"]; if (showMessageVal.isObject()) { const Json::Value& message = showMessageVal["message"]; const Json::Value& duration = showMessageVal["duration"]; if (message.isString() && duration.isInt()) { if (!textService_->isComposing()) { textService_->startComposition(session->context()); endComposition = true; } textService_->showMessage(session, utf8ToUtf16(message.asCString()), duration.asInt()); } } if (session != nullptr) { // if an edit session is available // handle candidate list const auto& showCandidatesVal = msg["showCandidates"]; if (showCandidatesVal.isBool()) { if (showCandidatesVal.asBool()) { // start composition if we are not composing. // this is required to get correctly position the candidate window if (!textService_->isComposing()) { textService_->startComposition(session->context()); } textService_->showCandidates(session); } else { textService_->hideCandidates(); } } const auto& candidateListVal = msg["candidateList"]; if (candidateListVal.isArray()) { // handle candidates // FIXME: directly access private member is dirty!!! vector<wstring>& candidates = textService_->candidates_; candidates.clear(); for (auto cand_it = candidateListVal.begin(); cand_it != candidateListVal.end(); ++cand_it) { wstring cand = utf8ToUtf16(cand_it->asCString()); candidates.push_back(cand); } textService_->updateCandidates(session); if (!showCandidatesVal.asBool()) { textService_->hideCandidates(); } } const auto& candidateCursorVal = msg["candidateCursor"]; if (candidateCursorVal.isInt()) { if (textService_->candidateWindow_ != nullptr) { textService_->candidateWindow_->setCurrentSel(candidateCursorVal.asInt()); textService_->refreshCandidates(); } } // handle comosition and commit strings const auto& commitStringVal = msg["commitString"]; if (commitStringVal.isString()) { std::wstring commitString = utf8ToUtf16(commitStringVal.asCString()); if (!commitString.empty()) { if (!textService_->isComposing()) { textService_->startComposition(session->context()); } textService_->setCompositionString(session, commitString.c_str(), commitString.length()); // FIXME: update the position of candidate and message window when the composition string is changed. if (textService_->candidateWindow_ != nullptr) { textService_->updateCandidatesWindow(session); } if (textService_->messageWindow_ != nullptr) { textService_->updateMessageWindow(session); } textService_->endComposition(session->context()); } } const auto& compositionStringVal = msg["compositionString"]; bool emptyComposition = false; bool hasCompositionString = false; std::wstring compositionString; if (compositionStringVal.isString()) { // composition buffer compositionString = utf8ToUtf16(compositionStringVal.asCString()); hasCompositionString = true; if (compositionString.empty()) { emptyComposition = true; if (textService_->isComposing() && !textService_->showingCandidates()) { // when the composition buffer is empty and we are not showing the candidate list, end composition. textService_->setCompositionString(session, L"", 0); endComposition = true; } } else { if (!textService_->isComposing()) { textService_->startComposition(session->context()); } textService_->setCompositionString(session, compositionString.c_str(), compositionString.length()); } // FIXME: update the position of candidate and message window when the composition string is changed. if (textService_->candidateWindow_ != nullptr) { textService_->updateCandidatesWindow(session); } if (textService_->messageWindow_ != nullptr) { textService_->updateMessageWindow(session); } } const auto& compositionCursorVal = msg["compositionCursor"]; if (compositionCursorVal.isInt()) { // composition cursor if (!emptyComposition) { int compositionCursor = compositionCursorVal.asInt(); if (!textService_->isComposing()) { textService_->startComposition(session->context()); } // NOTE: // This fixes PIME bug #166: incorrect handling of UTF-16 surrogate pairs. // The TSF API unfortunately treat a UTF-16 surrogate pair as two characters while // they actually represent one unicode character only. To workaround this TSF bug, // we get the composition string, and try to move the cursor twice when a UTF-16 // surrogate pair is found. if(!hasCompositionString) compositionString = textService_->compositionString(session); int fixedCursorPos = 0; for (int i = 0; i < compositionCursor; ++i) { ++fixedCursorPos; if (IS_HIGH_SURROGATE(compositionString[i])) // this is the first part of a UTF16 surrogate pair (Windows uses UTF16-LE) ++fixedCursorPos; } textService_->setCompositionCursor(session, fixedCursorPos); } } if (endComposition) { textService_->endComposition(session->context()); } } // language buttons const auto& addButtonVal = msg["addButton"]; if (addButtonVal.isArray()) { for (auto btn_it = addButtonVal.begin(); btn_it != addButtonVal.end(); ++btn_it) { const Json::Value& btn = *btn_it; // FIXME: when to clear the id <=> button map?? Ime::ComPtr<PIME::LangBarButton> langBtn{ PIME::LangBarButton::fromJson(textService_, btn), false }; if (langBtn != nullptr) { buttons_.emplace(langBtn->id(), langBtn); // insert into the map textService_->addButton(langBtn); } } } const auto& removeButtonVal = msg["removeButton"]; if (removeButtonVal.isArray()) { // FIXME: handle windows-mode-icon for (auto btn_it = removeButtonVal.begin(); btn_it != removeButtonVal.end(); ++btn_it) { if (btn_it->isString()) { string id = btn_it->asString(); auto map_it = buttons_.find(id); if (map_it != buttons_.end()) { textService_->removeButton(map_it->second); buttons_.erase(map_it); // remove from the map } } } } const auto& changeButtonVal = msg["changeButton"]; if (changeButtonVal.isArray()) { // FIXME: handle windows-mode-icon for (auto btn_it = changeButtonVal.begin(); btn_it != changeButtonVal.end(); ++btn_it) { const Json::Value& btn = *btn_it; if (btn.isObject()) { string id = btn["id"].asString(); auto map_it = buttons_.find(id); if (map_it != buttons_.end()) { map_it->second->updateFromJson(btn); } } } } // preserved keys const auto& addPreservedKeyVal = msg["addPreservedKey"]; if (addPreservedKeyVal.isArray()) { // preserved keys for (auto key_it = addPreservedKeyVal.begin(); key_it != addPreservedKeyVal.end(); ++key_it) { const Json::Value& key = *key_it; if (key.isObject()) { std::wstring guidStr = utf8ToUtf16(key["guid"].asCString()); CLSID guid = { 0 }; CLSIDFromString(guidStr.c_str(), &guid); UINT keyCode = key["keyCode"].asUInt(); UINT modifiers = key["modifiers"].asUInt(); textService_->addPreservedKey(keyCode, modifiers, guid); } } } const auto& removePreservedKeyVal = msg["removePreservedKey"]; if (removePreservedKeyVal.isArray()) { for (auto key_it = removePreservedKeyVal.begin(); key_it != removePreservedKeyVal.end(); ++key_it) { if (key_it->isString()) { std::wstring guidStr = utf8ToUtf16(key_it->asCString()); CLSID guid = { 0 }; CLSIDFromString(guidStr.c_str(), &guid); textService_->removePreservedKey(guid); } } } // keyboard status const auto& openKeyboardVal = msg["openKeyboard"]; if (openKeyboardVal.isBool()) { textService_->setKeyboardOpen(openKeyboardVal.asBool()); } // other configurations const auto& customizeUIVal = msg["customizeUI"]; if (customizeUIVal.isObject()) { // customize the UI updateUI(customizeUIVal); } // hide message const auto& hideMessageVal = msg["hideMessage"]; if (hideMessageVal.isBool()) { textService_->hideMessage(); } }
char *u8fgets(char *buf, int len, FILE *file) { wint_t c, c0; wchar_t ws[2 + 1]; char *b, *dst = NULL; if(file == stdin) { if(buf == NULL || len <= 0) return NULL; buf[0] = '\0'; c0 = L'\0'; while((c = fgetwc(file)) != WEOF) { if(IS_HIGH_SURROGATE(c0)) { if(IS_LOW_SURROGATE(c)) { ws[0] = c0; ws[1] = c; ws[2] = L'\0'; } else { ungetwc(c, file); ws[0] = c0; ws[1] = L'\0'; } } else if(IS_HIGH_SURROGATE(c)) { c0 = c; continue; } else { ws[0] = c; ws[1] = L'\0'; } c0 = L'\0'; b = u8wstos(ws); if(b) { if(len > (int)(strlen(buf) + strlen(b))) { strcat(buf, b); free(b); } else { free(b); if(ws[1] != L'\0') ungetwc(ws[1], file); if(ws[0] != L'\0') ungetwc(ws[0], file); break; } } if(c == L'\n') break; } if(c0 != L'\0') { ungetwc(c0, file); } if(strlen(buf) > 0) dst = buf; } else { dst = fgets(buf, len, file); } return dst; }
void nsHTMLContentSerializer::AppendToString(const nsAString& aStr, nsAString& aOutputStr, PRBool aTranslateEntities, PRBool aIncrColumn) { if (mBodyOnly && !mInBody) { return; } if (aIncrColumn) { mColPos += aStr.Length(); } if (aTranslateEntities && !mInCDATA) { if (mFlags & (nsIDocumentEncoder::OutputEncodeBasicEntities | nsIDocumentEncoder::OutputEncodeLatin1Entities | nsIDocumentEncoder::OutputEncodeHTMLEntities | nsIDocumentEncoder::OutputEncodeW3CEntities)) { nsIParserService* parserService = nsContentUtils::GetParserServiceWeakRef(); if (!parserService) { NS_ERROR("Can't get parser service"); return; } nsReadingIterator<PRUnichar> done_reading; aStr.EndReading(done_reading); // for each chunk of |aString|... PRUint32 advanceLength = 0; nsReadingIterator<PRUnichar> iter; const char **entityTable = mInAttribute ? kAttrEntities : kEntities; for (aStr.BeginReading(iter); iter != done_reading; iter.advance(PRInt32(advanceLength))) { PRUint32 fragmentLength = iter.size_forward(); PRUint32 lengthReplaced = 0; // the number of UTF-16 codepoints // replaced by a particular entity const PRUnichar* c = iter.get(); const PRUnichar* fragmentStart = c; const PRUnichar* fragmentEnd = c + fragmentLength; const char* entityText = nsnull; nsCAutoString entityReplacement; char* fullEntityText = nsnull; advanceLength = 0; // for each character in this chunk, check if it // needs to be replaced for (; c < fragmentEnd; c++, advanceLength++) { PRUnichar val = *c; if (val == kValNBSP) { entityText = kEntityNBSP; break; } else if ((val <= kGTVal) && (entityTable[val][0] != 0)) { entityText = entityTable[val]; break; } else if (val > 127 && ((val < 256 && mFlags & nsIDocumentEncoder::OutputEncodeLatin1Entities) || mFlags & nsIDocumentEncoder::OutputEncodeHTMLEntities)) { parserService->HTMLConvertUnicodeToEntity(val, entityReplacement); if (!entityReplacement.IsEmpty()) { entityText = entityReplacement.get(); break; } } else if (val > 127 && mFlags & nsIDocumentEncoder::OutputEncodeW3CEntities && mEntityConverter) { if (IS_HIGH_SURROGATE(val) && c + 1 < fragmentEnd && IS_LOW_SURROGATE(*(c + 1))) { PRUint32 valUTF32 = SURROGATE_TO_UCS4(val, *(++c)); if (NS_SUCCEEDED(mEntityConverter->ConvertUTF32ToEntity(valUTF32, nsIEntityConverter::entityW3C, &fullEntityText))) { lengthReplaced = 2; break; } else { advanceLength++; } } else if (NS_SUCCEEDED(mEntityConverter->ConvertToEntity(val, nsIEntityConverter::entityW3C, &fullEntityText))) { lengthReplaced = 1; break; } } } aOutputStr.Append(fragmentStart, advanceLength); if (entityText) { aOutputStr.Append(PRUnichar('&')); AppendASCIItoUTF16(entityText, aOutputStr); aOutputStr.Append(PRUnichar(';')); advanceLength++; } // if it comes from nsIEntityConverter, it already has '&' and ';' else if (fullEntityText) { AppendASCIItoUTF16(fullEntityText, aOutputStr); nsMemory::Free(fullEntityText); advanceLength += lengthReplaced; } } } else { nsXMLContentSerializer::AppendToString(aStr, aOutputStr, aTranslateEntities, aIncrColumn); } return; } aOutputStr.Append(aStr); }