static gchar* utf16ToUtf8(const UChar* aText, gint aLength, gint &length) { gboolean needCopy = FALSE; for (int i = 0; i < aLength; i++) { if (!aText[i] || IS_LOW_SURROGATE(aText[i])) { needCopy = TRUE; break; } if (IS_HIGH_SURROGATE(aText[i])) { if (i < aLength - 1 && IS_LOW_SURROGATE(aText[i+1])) i++; else { needCopy = TRUE; break; } } } GOwnPtr<UChar> copiedString; if (needCopy) { /* Pango doesn't correctly handle nuls. We convert them to 0xff. */ /* Also "validate" UTF-16 text to make sure conversion doesn't fail. */ copiedString.set(static_cast<UChar*>(g_memdup(aText, aLength * sizeof(aText[0])))); UChar* p = copiedString.get(); /* don't need to reset i */ for (int 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; } gchar* utf8Text; glong itemsWritten; utf8Text = g_utf16_to_utf8(reinterpret_cast<const gunichar2*>(aText), aLength, 0, &itemsWritten, 0); length = itemsWritten; return utf8Text; }
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; }
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); }