Beispiel #1
0
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);

}
Beispiel #2
0
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;
}
Beispiel #4
0
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;
}
Beispiel #5
0
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;
}
Beispiel #6
0
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;
}
Beispiel #7
0
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;
}
Beispiel #8
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();
	}
}
Beispiel #9
0
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);
}