STDMETHODIMP CustomDWriteRender::DrawGlyphRun( __maybenull void* clientDrawingContext, FLOAT baselineOriginX, FLOAT baselineOriginY, DWRITE_MEASURING_MODE measuringMode, __in DWRITE_GLYPH_RUN const* glyphRun, __in DWRITE_GLYPH_RUN_DESCRIPTION const* glyphRunDescription, __maybenull IUnknown* clientDrawingEffect ) { HRESULT hr; IDWriteGlyphRunAnalysis* glyphRunAnalysis; DWTextBox::DWTBContext* ctx = static_cast<DWTextBox::DWTBContext*>(clientDrawingContext); ci::Surface* finalSurface = ctx->surface; RECT textureBounds; hr = mDWriteFactory->CreateGlyphRunAnalysis(glyphRun,0.75f,NULL,DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC,DWRITE_MEASURING_MODE_GDI_CLASSIC,0.0f,0.0f,&glyphRunAnalysis); if(hr!=S_OK) { OutputDebugString(L"Error!\n"); } glyphRunAnalysis->GetAlphaTextureBounds(DWRITE_TEXTURE_CLEARTYPE_3x1,&textureBounds); int width = textureBounds.right-textureBounds.left; int height = textureBounds.bottom -textureBounds.top; ci::Surface surface(width,height,true,ci::SurfaceChannelOrder::ARGB); //surface.setPremultiplied(true); uint8_t *dataAlpha = static_cast<uint8_t*>(malloc(width*height*4)); uint8_t *data = static_cast<uint8_t*>(malloc(width*height*3)); DWRITE_FONT_METRICS fontMetrics; glyphRun->fontFace->GetMetrics(&fontMetrics); glyphRunAnalysis->CreateAlphaTexture(DWRITE_TEXTURE_CLEARTYPE_3x1,&textureBounds,data,width*height*3); Concurrency::parallel_for(0,width*height,[&](int i){ float combAlpha = (data[i*3] + data[i*3+1] +data[i*3+2])/3; float scale = combAlpha/255; dataAlpha[i*4+0] = combAlpha; dataAlpha[i*4+1] = 255*scale;//data[i*3+0]; dataAlpha[i*4+2] = 255*scale;//data[i*3+0]; dataAlpha[i*4+3] = 255*scale;//data[i*3+0]; //dataAlpha[i*4+0] = (data[i*3] + data[i*3+1] +data[i*3+2])/3; }); memcpy(surface.getData(),dataAlpha,width*height*4); float ratio = (float)(glyphRun->fontEmSize)/(float)fontMetrics.designUnitsPerEm; float ascend = surface.getBounds().y2 + fontMetrics.descent*ratio; //finalSurface->copyFrom(surface,surface.getBounds(),Vec2i(baselineOriginX,baselineOriginY-ascend)); ci::ip::blend(finalSurface,surface,surface.getBounds(),Vec2i(baselineOriginX+textureBounds.left,baselineOriginY+textureBounds.top)); //mTexture = gl::Texture(surface); free (data); free (dataAlpha); return S_OK; }
QImage QFontEngineDirectWrite::imageForGlyph(glyph_t t, QFixed subPixelPosition, int margin, const QTransform &xform) { UINT16 glyphIndex = t; FLOAT glyphAdvance = 0; DWRITE_GLYPH_OFFSET glyphOffset; glyphOffset.advanceOffset = 0; glyphOffset.ascenderOffset = 0; DWRITE_GLYPH_RUN glyphRun; glyphRun.fontFace = m_directWriteFontFace; glyphRun.fontEmSize = fontDef.pixelSize; glyphRun.glyphCount = 1; glyphRun.glyphIndices = &glyphIndex; glyphRun.glyphAdvances = &glyphAdvance; glyphRun.isSideways = false; glyphRun.bidiLevel = 0; glyphRun.glyphOffsets = &glyphOffset; DWRITE_MATRIX transform; transform.dx = subPixelPosition.toReal(); transform.dy = 0; transform.m11 = xform.m11(); transform.m12 = xform.m12(); transform.m21 = xform.m21(); transform.m22 = xform.m22(); IDWriteGlyphRunAnalysis *glyphAnalysis = NULL; HRESULT hr = m_directWriteFactory->CreateGlyphRunAnalysis( &glyphRun, 1.0f, &transform, DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC, DWRITE_MEASURING_MODE_NATURAL, 0.0, 0.0, &glyphAnalysis ); if (SUCCEEDED(hr)) { RECT rect; glyphAnalysis->GetAlphaTextureBounds(DWRITE_TEXTURE_CLEARTYPE_3x1, &rect); rect.left -= margin; rect.top -= margin; rect.right += margin; rect.bottom += margin; int width = rect.right - rect.left; int height = rect.bottom - rect.top; int size = width * height * 3; if (size > 0) { BYTE *alphaValues = new BYTE[size]; qMemSet(alphaValues, size, 0); hr = glyphAnalysis->CreateAlphaTexture(DWRITE_TEXTURE_CLEARTYPE_3x1, &rect, alphaValues, size); if (SUCCEEDED(hr)) { QImage img(width, height, QImage::Format_RGB32); img.fill(0xffffffff); for (int y=0; y<height; ++y) { uint *dest = reinterpret_cast<uint *>(img.scanLine(y)); BYTE *src = alphaValues + width * 3 * y; for (int x=0; x<width; ++x) { dest[x] = *(src) << 16 | *(src + 1) << 8 | *(src + 2); src += 3; } } delete[] alphaValues; glyphAnalysis->Release(); return img; } else { delete[] alphaValues; glyphAnalysis->Release(); qErrnoWarning("QFontEngineDirectWrite::imageForGlyph: CreateAlphaTexture failed"); } } } else { qErrnoWarning("QFontEngineDirectWrite::imageForGlyph: CreateGlyphRunAnalysis failed"); } return QImage(); }
QImage QWindowsFontEngineDirectWrite::imageForGlyph(glyph_t t, QFixed subPixelPosition, int margin, const QTransform &xform) { glyph_metrics_t metrics = QFontEngine::boundingBox(t, xform); int width = (metrics.width + margin * 2 + 4).ceil().toInt() ; int height = (metrics.height + margin * 2 + 4).ceil().toInt(); UINT16 glyphIndex = t; FLOAT glyphAdvance = metrics.xoff.toReal(); DWRITE_GLYPH_OFFSET glyphOffset; glyphOffset.advanceOffset = 0; glyphOffset.ascenderOffset = 0; DWRITE_GLYPH_RUN glyphRun; glyphRun.fontFace = m_directWriteFontFace; glyphRun.fontEmSize = fontDef.pixelSize; glyphRun.glyphCount = 1; glyphRun.glyphIndices = &glyphIndex; glyphRun.glyphAdvances = &glyphAdvance; glyphRun.isSideways = false; glyphRun.bidiLevel = 0; glyphRun.glyphOffsets = &glyphOffset; QFixed x = margin - metrics.x.floor() + subPixelPosition; QFixed y = margin - metrics.y.floor(); DWRITE_MATRIX transform; transform.dx = x.toReal(); transform.dy = y.toReal(); transform.m11 = xform.m11(); transform.m12 = xform.m12(); transform.m21 = xform.m21(); transform.m22 = xform.m22(); IDWriteGlyphRunAnalysis *glyphAnalysis = NULL; HRESULT hr = m_fontEngineData->directWriteFactory->CreateGlyphRunAnalysis( &glyphRun, 1.0f, &transform, DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC, DWRITE_MEASURING_MODE_NATURAL, 0.0, 0.0, &glyphAnalysis ); if (SUCCEEDED(hr)) { RECT rect; rect.left = 0; rect.top = 0; rect.right = width; rect.bottom = height; int size = width * height * 3; BYTE *alphaValues = new BYTE[size]; memset(alphaValues, size, 0); hr = glyphAnalysis->CreateAlphaTexture(DWRITE_TEXTURE_CLEARTYPE_3x1, &rect, alphaValues, size); if (SUCCEEDED(hr)) { QImage img(width, height, QImage::Format_RGB32); img.fill(0xffffffff); for (int y=0; y<height; ++y) { uint *dest = reinterpret_cast<uint *>(img.scanLine(y)); BYTE *src = alphaValues + width * 3 * y; for (int x=0; x<width; ++x) { dest[x] = *(src) << 16 | *(src + 1) << 8 | *(src + 2); src += 3; } } delete[] alphaValues; glyphAnalysis->Release(); return img; } else { delete[] alphaValues; glyphAnalysis->Release(); qErrnoWarning("%s: CreateAlphaTexture failed", __FUNCTION__); } } else { qErrnoWarning("%s: CreateGlyphRunAnalysis failed", __FUNCTION__); } return QImage(); }
cairo_warn cairo_int_status_t _cairo_dwrite_scaled_show_glyphs(void *scaled_font, cairo_operator_t op, const cairo_pattern_t *pattern, cairo_surface_t *generic_surface, int source_x, int source_y, int dest_x, int dest_y, unsigned int width, unsigned int height, cairo_glyph_t *glyphs, int num_glyphs, cairo_region_t *clip_region, int *remaining_glyphs) { cairo_win32_surface_t *surface = (cairo_win32_surface_t *)generic_surface; cairo_int_status_t status; if (width == 0 || height == 0) return (cairo_int_status_t)CAIRO_STATUS_SUCCESS; if (_cairo_surface_is_win32 (generic_surface) && surface->format == CAIRO_FORMAT_RGB24 && op == CAIRO_OPERATOR_OVER) { //XXX: we need to set the clip region here status = (cairo_int_status_t)_cairo_dwrite_show_glyphs_on_surface (surface, op, pattern, glyphs, num_glyphs, (cairo_scaled_font_t*)scaled_font, NULL); return status; } else { cairo_dwrite_scaled_font_t *dwritesf = static_cast<cairo_dwrite_scaled_font_t*>(scaled_font); UINT16 *indices = new UINT16[num_glyphs]; DWRITE_GLYPH_OFFSET *offsets = new DWRITE_GLYPH_OFFSET[num_glyphs]; FLOAT *advances = new FLOAT[num_glyphs]; BOOL transform = FALSE; DWRITE_GLYPH_RUN run; run.bidiLevel = 0; run.fontFace = ((cairo_dwrite_font_face_t*)dwritesf->base.font_face)->dwriteface; run.glyphIndices = indices; run.glyphCount = num_glyphs; run.isSideways = FALSE; run.glyphOffsets = offsets; run.glyphAdvances = advances; IDWriteGlyphRunAnalysis *analysis; if (dwritesf->mat.xy == 0 && dwritesf->mat.yx == 0 && dwritesf->mat.xx == dwritesf->base.font_matrix.xx && dwritesf->mat.yy == dwritesf->base.font_matrix.yy) { for (int i = 0; i < num_glyphs; i++) { indices[i] = (WORD) glyphs[i].index; // Since we will multiply by our ctm matrix later for rotation effects // and such, adjust positions by the inverse matrix now. offsets[i].ascenderOffset = (FLOAT)dest_y - (FLOAT)glyphs[i].y; offsets[i].advanceOffset = (FLOAT)glyphs[i].x - dest_x; advances[i] = 0.0; } run.fontEmSize = (FLOAT)dwritesf->base.font_matrix.yy; } else { transform = TRUE; for (int i = 0; i < num_glyphs; i++) { indices[i] = (WORD) glyphs[i].index; double x = glyphs[i].x - dest_x; double y = glyphs[i].y - dest_y; cairo_matrix_transform_point(&dwritesf->mat_inverse, &x, &y); // Since we will multiply by our ctm matrix later for rotation effects // and such, adjust positions by the inverse matrix now. offsets[i].ascenderOffset = -(FLOAT)y; offsets[i].advanceOffset = (FLOAT)x; advances[i] = 0.0; } run.fontEmSize = 1.0f; } if (!transform) { DWriteFactory::Instance()->CreateGlyphRunAnalysis(&run, 1.0f, NULL, DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC, DWRITE_MEASURING_MODE_NATURAL, 0, 0, &analysis); } else { DWRITE_MATRIX dwmatrix = _cairo_dwrite_matrix_from_matrix(&dwritesf->mat); DWriteFactory::Instance()->CreateGlyphRunAnalysis(&run, 1.0f, &dwmatrix, DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC, DWRITE_MEASURING_MODE_NATURAL, 0, 0, &analysis); } RECT r; r.left = 0; r.top = 0; r.right = width; r.bottom = height; BYTE *surface = new BYTE[width * height * 3]; analysis->CreateAlphaTexture(DWRITE_TEXTURE_CLEARTYPE_3x1, &r, surface, width * height * 3); cairo_image_surface_t *mask_surface = (cairo_image_surface_t*)cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height); cairo_surface_flush(&mask_surface->base); for (unsigned int y = 0; y < height; y++) { for (unsigned int x = 0; x < width; x++) { mask_surface->data[y * mask_surface->stride + x * 4] = surface[y * width * 3 + x * 3 + 1]; mask_surface->data[y * mask_surface->stride + x * 4 + 1] = surface[y * width * 3 + x * 3 + 1]; mask_surface->data[y * mask_surface->stride + x * 4 + 2] = surface[y * width * 3 + x * 3 + 1]; mask_surface->data[y * mask_surface->stride + x * 4 + 3] = surface[y * width * 3 + x * 3 + 1]; } } cairo_surface_mark_dirty(&mask_surface->base); pixman_image_set_component_alpha(mask_surface->pixman_image, 1); cairo_surface_pattern_t mask; _cairo_pattern_init_for_surface (&mask, &mask_surface->base); status = (cairo_int_status_t)_cairo_surface_composite (op, pattern, &mask.base, generic_surface, source_x, source_y, 0, 0, dest_x, dest_y, width, height, clip_region); _cairo_pattern_fini (&mask.base); analysis->Release(); delete [] surface; delete [] indices; delete [] offsets; delete [] advances; cairo_surface_destroy (&mask_surface->base); *remaining_glyphs = 0; return (cairo_int_status_t)CAIRO_STATUS_SUCCESS; } }