void QVGPixmapDropShadowFilter::draw(QPainter *painter, const QPointF &dest, const QPixmap &src, const QRectF &srcRect) const { if (src.isNull()) return; if (src.pixmapData()->classId() != QPixmapData::OpenVGClass) { // The pixmap data is not an instance of QVGPixmapData, so fall // back to the default drop shadow filter implementation. QPixmapDropShadowFilter::draw(painter, dest, src, srcRect); return; } QVGPixmapData *pd = static_cast<QVGPixmapData *>(src.pixmapData()); VGImage srcImage = pd->toVGImage(); if (srcImage == VG_INVALID_HANDLE) return; QSize size = pd->size(); VGImage dstImage = QVGImagePool::instance()->createTemporaryImage (VG_A_8, size.width(), size.height(), VG_IMAGE_QUALITY_FASTER, pd); if (dstImage == VG_INVALID_HANDLE) return; // Clamp the radius range. We divide by 2 because the OpenVG blur // is "too blurry" compared to the default raster implementation. VGfloat maxRadius = VGfloat(vgGeti(VG_MAX_GAUSSIAN_STD_DEVIATION)); VGfloat radiusF = VGfloat(blurRadius()) / 2.0f; if (radiusF < 0.001f) radiusF = 0.001f; else if (radiusF > maxRadius) radiusF = maxRadius; // Blur the blackened source image. vgGaussianBlur(dstImage, srcImage, radiusF, radiusF, VG_TILE_PAD); VGImage child = VG_INVALID_HANDLE; QRect srect; if (srcRect.isNull() || (srcRect.topLeft().isNull() && srcRect.size() == size)) { child = dstImage; srect = QRect(0, 0, size.width(), size.height()); } else { srect = srcRect.toRect(); child = vgChildImage(dstImage, srect.x(), srect.y(), srect.width(), srect.height()); } qt_vg_drawVGImageStencil(painter, dest + offset(), child, color()); if(child != dstImage) vgDestroyImage(child); QVGImagePool::instance()->releaseImage(0, dstImage); // Now draw the actual pixmap over the top. painter->drawPixmap(dest, src, srect); }
void QVGPixmapBlurFilter::draw(QPainter *painter, const QPointF &dest, const QPixmap &src, const QRectF &srcRect) const { if (src.isNull()) return; if (src.pixmapData()->classId() != QPixmapData::OpenVGClass) { // The pixmap data is not an instance of QVGPixmapData, so fall // back to the default blur filter implementation. QPixmapBlurFilter::draw(painter, dest, src, srcRect); return; } QVGPixmapData *pd = static_cast<QVGPixmapData *>(src.pixmapData()); VGImage srcImage = pd->toVGImage(); if (srcImage == VG_INVALID_HANDLE) return; QSize size = pd->size(); VGImage dstImage = QVGImagePool::instance()->createTemporaryImage (VG_sARGB_8888_PRE, size.width(), size.height(), VG_IMAGE_QUALITY_FASTER, pd); if (dstImage == VG_INVALID_HANDLE) return; // Clamp the radius range. We divide by 2 because the OpenVG blur // is "too blurry" compared to the default raster implementation. VGfloat maxRadius = VGfloat(vgGeti(VG_MAX_GAUSSIAN_STD_DEVIATION)); VGfloat radiusF = VGfloat(radius()) / 2.0f; if (radiusF < 0.001f) radiusF = 0.001f; else if (radiusF > maxRadius) radiusF = maxRadius; vgGaussianBlur(dstImage, srcImage, radiusF, radiusF, VG_TILE_PAD); VGImage child = VG_INVALID_HANDLE; if (srcRect.isNull() || (srcRect.topLeft().isNull() && srcRect.size() == size)) { child = dstImage; } else { QRect src = srcRect.toRect(); child = vgChildImage(dstImage, src.x(), src.y(), src.width(), src.height()); } qt_vg_drawVGImage(painter, dest, child); if(child != dstImage) vgDestroyImage(child); QVGImagePool::instance()->releaseImage(0, dstImage); }
void CHuiFxVg10BlurFilter::DrawEffect(CHuiFxEngine& aEngine, VGImage aTargetImage, VGImage aSourceImage, TInt aWidth, TInt aHeight, TBool /*aHasSurface*/) { const VGfloat blur_x = clamp(iBlurX, EPSILON, 128.0f); const VGfloat blur_y = clamp(iBlurY, EPSILON, 128.0f); const VGfloat opacity = clamp(iOpacity, 0.0f, 1.0f); if(opacity < 1.0f - EPSILON) // slow path --- take opacity into account { // const VGint width = vgGetParameteri(aSourceImage, VG_IMAGE_WIDTH); // const VGint height = vgGetParameteri(aSourceImage, VG_IMAGE_HEIGHT); const VGint width = aWidth; const VGint height = aHeight; CHuiFxRenderbuffer* auxBuffer = aEngine.AcquireRenderbuffer(TSize(width, height)); if (!auxBuffer) { return; // not enough memory --- filter not completed successfully } auxBuffer->BindAsTexture(ERenderbufferUsageReadWrite); VGImage auxImage = reinterpret_cast<CHuiFxVg10RenderbufferBase*>(auxBuffer)->Image(); vgGaussianBlur(auxImage, aSourceImage, blur_x, blur_y, VG_TILE_PAD); if(OpacityChanged()) { UpdateAlphaLUT(); } vgLookup(aTargetImage, auxImage, iColorLUT, iColorLUT, iColorLUT, iAlphaLUT, VG_TRUE, VG_FALSE); auxBuffer->UnbindAsTexture(); aEngine.ReleaseRenderbuffer(auxBuffer); } else // fast path --- the blur, just blur and nothing but the blur. { vgGaussianBlur(aTargetImage, aSourceImage, blur_x, blur_y, VG_TILE_PAD); } }
void SubtitleRenderer::load_glyph(char32_t codepoint) { VGfloat escapement[2]{}; auto load_glyph_internal = [&](FT_Face ft_face, VGFont vg_font, bool border) { try { auto glyph_index = FT_Get_Char_Index(ft_face, codepoint); ENFORCE(!FT_Load_Glyph(ft_face, glyph_index, FT_LOAD_NO_HINTING)); FT_Glyph glyph; ENFORCE(!FT_Get_Glyph(ft_face->glyph, &glyph)); SCOPE_EXIT {FT_Done_Glyph(glyph);}; if (border) ENFORCE(!FT_Glyph_StrokeBorder(&glyph, ft_stroker_, 0, 1)); ENFORCE(!FT_Glyph_To_Bitmap(&glyph, FT_RENDER_MODE_NORMAL, NULL, 1)); FT_BitmapGlyph bit_glyph = (FT_BitmapGlyph) glyph; FT_Bitmap& bitmap = bit_glyph->bitmap; VGImage image{}; VGfloat glyph_origin[2]{}; if (bitmap.width > 0 && bitmap.rows > 0) { constexpr VGfloat blur_stddev = 0.6; const int padding = static_cast<int>(3*blur_stddev + 0.5); const int image_width = bitmap.width + padding*2; const int image_height = bitmap.rows + padding*2; image = vgCreateImage(VG_A_8, image_width, image_height, VG_IMAGE_QUALITY_NONANTIALIASED); assert(image); if (bitmap.pitch > 0) { vgImageSubData(image, bitmap.buffer + bitmap.pitch*(bitmap.rows-1), -bitmap.pitch, VG_A_8, padding, padding, bitmap.width, bitmap.rows); assert(!vgGetError()); } else { vgImageSubData(image, bitmap.buffer, bitmap.pitch, VG_A_8, padding, padding, bitmap.width, bitmap.rows); assert(!vgGetError()); } auto softened_image = vgCreateImage(VG_A_8, image_width, image_height, VG_IMAGE_QUALITY_NONANTIALIASED); assert(image); // Even out hard and soft edges vgGaussianBlur(softened_image, image, blur_stddev, blur_stddev, VG_TILE_FILL); assert(!vgGetError()); vgDestroyImage(image); assert(!vgGetError()); image = softened_image; glyph_origin[0] = static_cast<VGfloat>(padding - bit_glyph->left); glyph_origin[1] = static_cast<VGfloat>(padding + bitmap.rows - bit_glyph->top - 1); } escapement[0] = static_cast<VGfloat>((ft_face->glyph->advance.x + 32) / 64); escapement[1] = 0; vgSetGlyphToImage(vg_font, codepoint, image, glyph_origin, escapement); assert(!vgGetError()); if (image) { vgDestroyImage(image); assert(!vgGetError()); } } catch(...) { escapement[0] = 0; escapement[1] = 0; vgSetGlyphToImage(vg_font, codepoint, VG_INVALID_HANDLE, escapement, escapement); assert(!vgGetError()); } }; load_glyph_internal(ft_face_, vg_font_, false); glyphs_[codepoint].advance = escapement[0]; load_glyph_internal(ft_face_, vg_font_border_, true); }
int createFont(FT_Face fontFace, FT_UInt size) { initFreeTypeLibrary(); VGfloat glyphOrigin[2]; VGfloat escapement[2]; FT_Stroker fontStroker; int error = FT_Stroker_New(freeTypeLibrary, &fontStroker); if (error) { logInfo(LOG_FREETYPE, "Error FT_Stroker_New.(error=%d)\n", error); return -1; } FT_Stroker_Set(fontStroker, 2*64.0f, // Need to get the right value based on size. FT_STROKER_LINECAP_ROUND, FT_STROKER_LINEJOIN_ROUND, 0); VGFont tmpFont; struct fontListItem *tmpFontListItem = fontExists(fontFace, size); if (tmpFontListItem == NULL) { tmpFont = vgCreateFont(fontFace->num_glyphs); if (tmpFont == VG_INVALID_HANDLE) { logInfo(LOG_FREETYPE, "Error could not create vgCreateFont.\n"); return -1; } tmpFontListItem = malloc(sizeof(struct fontListItem)); tmpFontListItem->fontFace = fontFace; tmpFontListItem->size = size; tmpFontListItem->font = tmpFont; addToFontList(tmpFontListItem); } else { return 0; } error = FT_Set_Char_Size( fontFace, /* handle to face object */ 0, /* char_width in 1/64th of points */ size*64, /* char_height in 1/64th of points */ 72, /* horizontal device resolution */ 72 ); /* vertical device resolution */ if (error) { logInfo(LOG_FREETYPE, "Error FT_Set_Char_Size.(error=%d)\n", error); return -1; } int index; int counter = 0; FT_UInt charIndex; VGImage image = VG_INVALID_HANDLE; VGImage softenedImage; VGfloat blustStdDev; int padding; int image_width; int image_height; VGErrorCode vg_error; FT_Glyph glyph; logInfo(LOG_FREETYPE, "This font contains %ld glyphs.\n", fontFace->num_glyphs); for (index = 32; (index < 256) && (counter < fontFace->num_glyphs); index++) { counter++; charIndex = FT_Get_Char_Index(fontFace, index); logInfo(LOG_FREETYPE, "index=0x%x, charIndex=0x%x\n", index, charIndex); escapement[0] = 0; escapement[1] = 0; if (charIndex == 0) { vgSetGlyphToImage(tmpFont, index, VG_INVALID_HANDLE, escapement, escapement); logInfo(LOG_FREETYPE, "charindex== 0\n"); continue; } error = FT_Load_Glyph(fontFace, charIndex, FT_LOAD_NO_HINTING); if (error) { vgSetGlyphToImage(tmpFont, index, VG_INVALID_HANDLE, escapement, escapement); logInfo(LOG_FREETYPE, "Error FT_Load_Glyph (error:%d)\n", error); continue; } error = FT_Get_Glyph(fontFace->glyph, &glyph); if (error) { vgSetGlyphToImage(tmpFont, index, VG_INVALID_HANDLE, escapement, escapement); logInfo(LOG_FREETYPE, "Error FT_Get_Glyph (error:%d)\n", error); continue; } /* error = FT_Glyph_StrokeBorder(&glyph, fontStroker, 0, 1); if (error) { FT_Done_Glyph(glyph); vgSetGlyphToImage(tmpFont, index, VG_INVALID_HANDLE, escapement, escapement); logInfo(LOG_FREETYPE, "Error FT_Glyph_StrokeBorder (error:%d)\n", error); continue; } */ error = FT_Glyph_To_Bitmap(&glyph, FT_RENDER_MODE_NORMAL, NULL, 1); if (error) { FT_Done_Glyph(glyph); vgSetGlyphToImage(tmpFont, index, VG_INVALID_HANDLE, escapement, escapement); logInfo(LOG_FREETYPE, "Error FT_Glyph_To_Bitmap (error:%d)\n", error); continue; } FT_BitmapGlyph bitGlyph = (FT_BitmapGlyph)glyph; FT_Bitmap bitmap = bitGlyph->bitmap; if (bitmap.width > 0 && bitmap.rows > 0) { blustStdDev = 0.6; padding = (3*blustStdDev + 0.5); image_width = bitmap.width + padding*2; image_height = bitmap.rows + padding*2; image = vgCreateImage(VG_A_8, image_width, image_height, VG_IMAGE_QUALITY_NONANTIALIASED); if (image == VG_INVALID_HANDLE) { FT_Done_Glyph(glyph); vgSetGlyphToImage(tmpFont, index, VG_INVALID_HANDLE, escapement, escapement); logInfo(LOG_FREETYPE, "vgCreateImage (error:%d)\n", vgGetError()); continue; } if (bitmap.pitch > 0) { vgImageSubData(image, bitmap.buffer + bitmap.pitch*(bitmap.rows-1), -bitmap.pitch, VG_A_8, padding, padding, bitmap.width, bitmap.rows); } else { vgImageSubData(image, bitmap.buffer, bitmap.pitch, VG_A_8, padding, padding, bitmap.width, bitmap.rows); } vg_error = vgGetError(); if (vg_error) { vgDestroyImage(image); FT_Done_Glyph(glyph); vgSetGlyphToImage(tmpFont, index, VG_INVALID_HANDLE, escapement, escapement); showVGErrorStr(vg_error, "vgImageSubData"); continue; } softenedImage = vgCreateImage(VG_A_8, image_width, image_height, VG_IMAGE_QUALITY_NONANTIALIASED); if (softenedImage == VG_INVALID_HANDLE) { vgDestroyImage(image); FT_Done_Glyph(glyph); vgSetGlyphToImage(tmpFont, index, VG_INVALID_HANDLE, escapement, escapement); logInfo(LOG_FREETYPE, "vgCreateImage (error:%d)\n", vgGetError()); continue; } // Even out hard and soft edges vgGaussianBlur(softenedImage, image, blustStdDev, blustStdDev, VG_TILE_FILL); vg_error = vgGetError(); if (vg_error) { vgDestroyImage(softenedImage); vgDestroyImage(image); FT_Done_Glyph(glyph); vgSetGlyphToImage(tmpFont, index, VG_INVALID_HANDLE, escapement, escapement); showVGErrorStr(vg_error, "vgGaussianBlur"); continue; } vgDestroyImage(image); image = softenedImage; glyphOrigin[0] = (VGfloat)(padding - bitGlyph->left); glyphOrigin[1] = (VGfloat)(padding + bitmap.rows - bitGlyph->top - 1); } else { logInfo(LOG_FREETYPE, "Error bitmap.width = %d, bitmap.rows = %d\n", bitmap.width, bitmap.rows); } escapement[0] = (VGfloat)((fontFace->glyph->advance.x + 32) / 64); escapement[1] = 0; vgSetGlyphToImage(tmpFont, index, image, glyphOrigin, escapement); vg_error = vgGetError(); if (vg_error) { vgDestroyImage(softenedImage); vgDestroyImage(image); FT_Done_Glyph(glyph); vgSetGlyphToImage(tmpFont, index, VG_INVALID_HANDLE, escapement, escapement); showVGErrorStr(vg_error, "vgSetGlyphToImage"); continue; } logInfo(LOG_FREETYPE, "Create glyph %d.\n", index); FT_Done_Glyph(glyph); if (image != VG_INVALID_HANDLE) { vgDestroyImage(image); } } return 0; }