void wxSVGCanvasCairo::DrawCanvasPath(wxSVGCanvasPathCairo& canvasPath, wxSVGMatrix& matrix, const wxCSSStyleDeclaration& style, wxSVGSVGElement& svgElem) { // check Filter if (style.GetFilter().GetCSSPrimitiveType() == wxCSS_URI && style.GetFilter().GetStringValue().length() > 1) { wxString filterId = style.GetFilter().GetStringValue().substr(1); wxSVGElement* filterElem = (wxSVGElement*) svgElem.GetElementById(filterId); // feGaussianBlur if (filterElem && filterElem->GetDtd() == wxSVG_FILTER_ELEMENT && filterElem->GetFirstChild() != NULL && ((wxSVGSVGElement*) filterElem->GetFirstChild())->GetDtd() == wxSVG_FEGAUSSIANBLUR_ELEMENT) { float stdX = ((wxSVGFEGaussianBlurElement*) filterElem->GetFirstChild())->GetStdDeviationX().GetAnimVal(); float stdY = ((wxSVGFEGaussianBlurElement*) filterElem->GetFirstChild())->GetStdDeviationY().GetAnimVal(); if (stdX <= 0 || stdY <= 0) return; int dx = int(floor(stdX * 3 * sqrt(2 * M_PI) / 4 + 0.5)); int dy = int(floor(stdY * 3 * sqrt(2 * M_PI) / 4 + 0.5)); wxSVGRect rect = canvasPath.GetResultBBox(style, matrix.Inverse()); rect.SetX(rect.GetX() - 2*dx); rect.SetY(rect.GetY() - 2*dy); rect.SetWidth(rect.GetWidth() + 4*dx); rect.SetHeight(rect.GetHeight() + 4*dy); int width = (int) rect.GetWidth(); int height = (int) rect.GetHeight(); cairo_surface_t* surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height); cairo_t* cr = cairo_create(surface); wxSVGMatrix matrix2 = wxSVGMatrix(1, 0, 0, 1, - rect.GetX(), - rect.GetY()).Multiply(matrix); DrawPath(cr, canvasPath, matrix2, style, svgElem); gaussianBlur(surface, dx, dy); // draw surface cairo_save(m_cr); SetMatrix(m_cr, wxSVGMatrix(1, 0, 0, 1, rect.GetX(), rect.GetY())); cairo_set_source_surface(m_cr, surface, 0, 0); cairo_rectangle(m_cr, 0, 0, width, height); cairo_paint(m_cr); // fill the rectangle using the pattern cairo_new_path(m_cr); cairo_restore(m_cr); cairo_destroy(cr); cairo_surface_destroy(surface); return; } } DrawPath(m_cr, canvasPath, matrix, style, svgElem); }
void wxSVGCanvasCairo::DrawMarker(const wxString& uri, wxSVGMark::Type type, wxSVGCanvasPathCairo& canvasPath, const wxSVGMatrix& matrix, const wxCSSStyleDeclaration& style, wxSVGSVGElement& svgElem) { wxSVGMarkerElement* markerElem = GetMarkerElement(svgElem, uri); if (markerElem == NULL || markerElem->GetMarkerWidth().GetAnimVal() <= 0 || markerElem->GetMarkerHeight().GetAnimVal() <= 0) return; vector<wxSVGMark> markPoints = canvasPath.GetMarkPoints(); for (vector<wxSVGMark>::iterator it = markPoints.begin(); it != markPoints.end(); it++) { if (it->type != type) continue; wxSVGMark& markPoint = *it; double scaleX = matrix.GetA() * style.GetStrokeWidth(); double scaleY = matrix.GetD() * style.GetStrokeWidth(); markerElem->SetOwnerSVGElement(&svgElem); markerElem->SetViewportElement(&svgElem); cairo_surface_t* surface = cairo_image_surface_create( CAIRO_FORMAT_ARGB32, lround(markerElem->GetMarkerWidth().GetAnimVal() * scaleX), lround(markerElem->GetMarkerHeight().GetAnimVal() * scaleY)); cairo_t* cr = cairo_create(surface); wxSVGMatrix markerMatrix; markerMatrix = markerMatrix.ScaleNonUniform(scaleX, scaleY); wxCSSStyleDeclaration style; DrawMask(cr, markerElem, markerMatrix, style, svgElem); // draw surface cairo_save(m_cr); double refX = markerElem->GetRefX().GetAnimVal() * style.GetStrokeWidth(); double refY = markerElem->GetRefY().GetAnimVal() * style.GetStrokeWidth(); wxSVGPoint point(markPoint.x - refX, markPoint.y - refY); point = point.MatrixTransform(matrix); wxSVGMatrix m; m = m.Translate(point.GetX(), point.GetY()); if (markPoint.angle != 0) { refX = markerElem->GetRefX().GetAnimVal() * scaleX; refY = markerElem->GetRefY().GetAnimVal() * scaleY; m = m.Translate(refX, refY).Rotate(markPoint.angle / M_PI * 180).Translate(-refX, -refY); } SetMatrix(m_cr, m); cairo_set_source_surface(m_cr, surface, 0, 0); cairo_paint(m_cr); cairo_restore(m_cr); cairo_destroy(cr); cairo_surface_destroy(surface); } }
wxSVGRect wxSVGCanvasPathCairo::GetResultBBox(const wxCSSStyleDeclaration& style, const wxSVGMatrix& matrix) { if (&matrix) { cairo_matrix_t m; cairo_matrix_init(&m, matrix.GetA(), matrix.GetB(), matrix.GetC(), matrix.GetD(), matrix.GetE(), matrix.GetF()); cairo_set_matrix(m_cr, &m); } ApplyStrokeStyle(m_cr, style); double x1, y1, x2, y2; if (style.GetStrokeWidth() > 0) cairo_stroke_extents(m_cr, &x1, &y1, &x2, &y2); else cairo_fill_extents(m_cr, &x1, &y1, &x2, &y2); if (&matrix) { cairo_matrix_t mat; cairo_matrix_init(&mat, 1, 0, 0, 1, 0, 0); cairo_set_matrix(m_cr, &mat); } return wxSVGRect(x1, y1, x2 - x1, y2 - y1); }
void wxSVGCanvasPathCairo::ApplyStrokeStyle(cairo_t* cr, const wxCSSStyleDeclaration& style) { cairo_set_line_width(cr, style.GetStrokeWidth()); switch (style.GetStrokeLinecap()) { case wxCSS_VALUE_ROUND: cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND); break; case wxCSS_VALUE_SQUARE: cairo_set_line_cap(cr, CAIRO_LINE_CAP_SQUARE); break; case wxCSS_VALUE_BUTT: default: cairo_set_line_cap(cr, CAIRO_LINE_CAP_BUTT); break; } switch (style.GetStrokeLinejoin()) { case wxCSS_VALUE_BEVEL: cairo_set_line_join(cr, CAIRO_LINE_JOIN_BEVEL); break; case wxCSS_VALUE_ROUND: cairo_set_line_join(cr, CAIRO_LINE_JOIN_ROUND); break; case wxCSS_VALUE_MITER: default: cairo_set_line_join(cr, CAIRO_LINE_JOIN_MITER); break; } if (style.GetStrokeDasharray().GetLength() > 0) { double* dashed = new double[style.GetStrokeDasharray().GetLength()]; for (int i = 0; i < style.GetStrokeDasharray().GetLength(); i++) { dashed[i] = style.GetStrokeDasharray().Item(i).GetFloatValue(); } cairo_set_dash(cr, dashed, style.GetStrokeDasharray().GetLength(), 0.0); delete dashed; } else cairo_set_dash(cr, NULL, 0, 0); }
void wxSVGCanvasCairo::DrawCanvasImage(wxSVGCanvasImage& canvasImage, cairo_surface_t* cairoSurface, wxSVGMatrix& matrix, const wxCSSStyleDeclaration& style, wxSVGSVGElement& svgElem) { if (cairoSurface == NULL) return; cairo_save(m_cr); // ClipPath if (style.GetClipPath().GetCSSPrimitiveType() == wxCSS_URI && style.GetClipPath().GetStringValue().length() > 1) { wxString clipPathId = style.GetClipPath().GetStringValue().substr(1); wxSVGClipPathElement* clipPathElem = (wxSVGClipPathElement*) svgElem.GetElementById(clipPathId); if (clipPathElem && clipPathElem->GetDtd() == wxSVG_CLIPPATH_ELEMENT) { clipPathElem->SetOwnerSVGElement(&svgElem); clipPathElem->SetViewportElement(&svgElem); wxSVGMatrix clipMatrix(matrix); clipPathElem->UpdateMatrix(clipMatrix); SetClipPath(clipPathElem, clipMatrix); } } SetMatrix(m_cr, matrix); // scale context double x = canvasImage.m_x; double y = canvasImage.m_y; double scaleX = canvasImage.m_width / canvasImage.m_image.GetWidth(); double scaleY = canvasImage.m_height / canvasImage.m_image.GetHeight(); wxSVG_PRESERVEASPECTRATIO align = canvasImage.GetPreserveAspectRatio().GetAlign(); bool alignX = false; if (align > wxSVG_PRESERVEASPECTRATIO_NONE) { scaleY = canvasImage.m_height / canvasImage.GetDefaultHeight(); if (canvasImage.GetPreserveAspectRatio().GetMeetOrSlice() != wxSVG_MEETORSLICE_SLICE) { alignX = scaleX > scaleY; } else { cairo_rectangle(m_cr, x, y, canvasImage.m_width, canvasImage.m_height); cairo_clip(m_cr); alignX = scaleX < scaleY; } if (alignX) { scaleX = scaleY; if (align == wxSVG_PRESERVEASPECTRATIO_XMIDYMIN || align == wxSVG_PRESERVEASPECTRATIO_XMIDYMID || align == wxSVG_PRESERVEASPECTRATIO_XMIDYMAX) x += (canvasImage.m_width - canvasImage.GetDefaultWidth() * scaleX) / 2; else if (align == wxSVG_PRESERVEASPECTRATIO_XMAXYMIN || align == wxSVG_PRESERVEASPECTRATIO_XMAXYMID || align == wxSVG_PRESERVEASPECTRATIO_XMAXYMAX) x += canvasImage.m_width - canvasImage.GetDefaultWidth() * scaleX; } else { scaleY = scaleX; if (align == wxSVG_PRESERVEASPECTRATIO_XMINYMID || align == wxSVG_PRESERVEASPECTRATIO_XMIDYMID || align == wxSVG_PRESERVEASPECTRATIO_XMAXYMID) y += (canvasImage.m_height - canvasImage.GetDefaultHeight() * scaleY) / 2; else if (align == wxSVG_PRESERVEASPECTRATIO_XMINYMAX || align == wxSVG_PRESERVEASPECTRATIO_XMIDYMAX || align == wxSVG_PRESERVEASPECTRATIO_XMAXYMAX) y += canvasImage.m_height - canvasImage.GetDefaultHeight() * scaleY; } scaleY = scaleY * canvasImage.GetDefaultHeight() / canvasImage.m_image.GetHeight(); } cairo_translate(m_cr, x, y); cairo_scale(m_cr, scaleX, scaleY); // prepare to draw the image cairo_set_source_surface(m_cr, cairoSurface, 0, 0); // use the original size here since the context is scaled already... cairo_rectangle(m_cr, 0, 0, canvasImage.m_image.GetWidth(), canvasImage.m_image.GetHeight()); // paint if (style.GetMask().GetCSSPrimitiveType() == wxCSS_URI && style.GetMask().GetStringValue().length() > 1) { wxString maskId = style.GetMask().GetStringValue().substr(1); wxSVGMaskElement* maskElem = (wxSVGMaskElement*) svgElem.GetElementById(maskId); if (maskElem && maskElem->GetDtd() == wxSVG_MASK_ELEMENT) { maskElem->SetOwnerSVGElement(&svgElem); maskElem->SetViewportElement(&svgElem); cairo_surface_t* surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, svgElem.GetWidth().GetAnimVal()/scaleX, svgElem.GetHeight().GetAnimVal()/scaleY); cairo_t* cr = cairo_create(surface); wxSVGMatrix maskMatrix; maskMatrix = maskMatrix.Translate(x, y).ScaleNonUniform(scaleX, scaleY).Inverse(); DrawMask(cr, maskElem, maskMatrix, style, svgElem); cairo_mask_surface(m_cr, surface, 0, 0); cairo_destroy(cr); cairo_surface_destroy(surface); } } else { cairo_paint_with_alpha(m_cr, style.GetOpacity()); } cairo_new_path(m_cr); // clean up cairo_restore(m_cr); }
void wxSVGCanvasCairo::DrawPath(cairo_t* cr, wxSVGCanvasPathCairo& canvasPath, const wxSVGMatrix& matrix, const wxCSSStyleDeclaration& style, wxSVGSVGElement& svgElem) { SetMatrix(cr, matrix); // Filling if (canvasPath.GetFill() && style.GetFill().Ok() && style.GetFill().GetPaintType() != wxSVG_PAINTTYPE_NONE) { cairo_path_t* path = canvasPath.GetPath(); cairo_append_path(cr, path); SetPaint(cr, style.GetFill(), style.GetOpacity()*style.GetFillOpacity(), canvasPath, svgElem, matrix); cairo_fill(cr); cairo_path_destroy(path); } // Stroking if (style.GetStroke().Ok() && style.GetStrokeWidth() > 0 && style.GetStroke().GetPaintType() != wxSVG_PAINTTYPE_NONE) { cairo_path_t* path = canvasPath.GetPath(); cairo_append_path(cr, path); SetPaint(cr, style.GetStroke(), style.GetOpacity()*style.GetStrokeOpacity(), canvasPath, svgElem, matrix); wxSVGCanvasPathCairo::ApplyStrokeStyle(cr, style); cairo_stroke(cr); cairo_path_destroy(path); } // marker if (style.HasMarkerStart()) { DrawMarker(style.GetMarkerStart().GetStringValue(), wxSVGMark::START, canvasPath, matrix, style, svgElem); } if (style.HasMarkerMid()) { DrawMarker(style.GetMarkerMid().GetStringValue(), wxSVGMark::MID, canvasPath, matrix, style, svgElem); } if (style.HasMarkerEnd()) { DrawMarker(style.GetMarkerEnd().GetStringValue(), wxSVGMark::END, canvasPath, matrix, style, svgElem); } }
void wxSVGCanvasTextCairo::InitText(const wxString& text, const wxCSSStyleDeclaration& style, wxSVGMatrix* matrix) { BeginChar(matrix); // create path from text cairo_t* cr = ((wxSVGCanvasPathCairo*) m_char->path)->GetCr(); #if defined(__WXMSW__) || defined(__WXMAC__) int size = (int) style.GetFontSize(); int fstyle = style.GetFontStyle() == wxCSS_VALUE_ITALIC ? wxFONTSTYLE_ITALIC : (style.GetFontStyle() == wxCSS_VALUE_OBLIQUE ? wxFONTSTYLE_SLANT : wxFONTSTYLE_NORMAL); wxFontWeight weight = style.GetFontWeight() == wxCSS_VALUE_BOLD ? wxFONTWEIGHT_BOLD : style.GetFontWeight() == wxCSS_VALUE_BOLDER ? wxFONTWEIGHT_MAX : style.GetFontWeight() == wxCSS_VALUE_LIGHTER ? wxFONTWEIGHT_LIGHT : wxFONTWEIGHT_NORMAL; wxFont fnt(size, wxFONTFAMILY_DEFAULT, fstyle, weight, false, style.GetFontFamily()); #ifdef __WXMSW__ HFONT hfont = (HFONT) fnt.GetResourceHandle(); cairo_set_font_face(cr, cairo_win32_font_face_create_for_hfont(hfont)); #else CGFontRef cgFont = fnt.OSXGetCGFont(); cairo_set_font_face(cr, cairo_quartz_font_face_create_for_cgfont(cgFont)); #endif cairo_set_font_size(cr, style.GetFontSize()); cairo_font_extents_t fextents; cairo_font_extents(cr, &fextents); double maxWidth = 0; if (style.GetTextAnchor() == wxCSS_VALUE_MIDDLE || style.GetTextAnchor() == wxCSS_VALUE_END) { wxStringTokenizer tokenzr(text, wxT("\n")); while (tokenzr.HasMoreTokens()) { wxString token = tokenzr.GetNextToken(); cairo_text_extents_t extents; cairo_text_extents(cr, (const char*) token.utf8_str(), &extents); if (maxWidth < extents.width) maxWidth = extents.width; } } wxStringTokenizer tokenzr(text, wxT("\n")); double x_advance = 0; double width = 0; double height = 0; double y = 0; while (tokenzr.HasMoreTokens()) { wxString token = tokenzr.GetNextToken(); // get text extents cairo_text_extents_t extents; cairo_text_extents(cr, (const char*) token.utf8_str(), &extents); double x = style.GetTextAnchor() == wxCSS_VALUE_END ? maxWidth - extents.width : style.GetTextAnchor() == wxCSS_VALUE_MIDDLE ? (maxWidth - extents.width) / 2 : 0; m_char->path->MoveTo(m_tx + x, m_ty + y); cairo_text_path(cr, (const char*) token.utf8_str()); if (x_advance < extents.x_advance) x_advance = extents.x_advance; if (width < extents.width) width = extents.width; height += fextents.height; if (tokenzr.HasMoreTokens()) y += fextents.height; } // set bbox m_char->bbox = wxSVGRect(m_tx, m_ty, width, height); // increase current position (m_tx) if (style.GetTextAnchor() == wxCSS_VALUE_MIDDLE || style.GetTextAnchor() == wxCSS_VALUE_END) { wxSVGRect bbox = m_char->path->GetResultBBox(style); m_tx += x_advance > bbox.GetWidth() ? x_advance : bbox.GetWidth(); } else m_tx += x_advance; #else PangoLayout* layout = pango_cairo_create_layout(cr); PangoFontDescription* font = pango_font_description_new(); pango_font_description_set_family(font, style.GetFontFamily().ToAscii()); pango_font_description_set_weight(font, style.GetFontWeight() == wxCSS_VALUE_BOLD ? PANGO_WEIGHT_BOLD : PANGO_WEIGHT_NORMAL); pango_font_description_set_style(font, style.GetFontStyle() == wxCSS_VALUE_ITALIC ? PANGO_STYLE_ITALIC : (style.GetFontStyle() == wxCSS_VALUE_OBLIQUE ? PANGO_STYLE_OBLIQUE : PANGO_STYLE_NORMAL)); pango_font_description_set_absolute_size(font, style.GetFontSize() * PANGO_SCALE); PangoContext* ctx = pango_layout_get_context(layout); PangoFont* f = pango_context_load_font(ctx, font); if (f == NULL) pango_font_description_set_style(font, PANGO_STYLE_NORMAL); pango_layout_set_font_description(layout, font); if (style.GetTextAnchor() != wxCSS_VALUE_START) pango_layout_set_alignment(layout, style.GetTextAnchor() == wxCSS_VALUE_MIDDLE ? PANGO_ALIGN_CENTER : PANGO_ALIGN_RIGHT); pango_layout_set_text(layout, (const char*) text.utf8_str(), -1); int baseline = pango_layout_get_baseline(layout); m_char->path->MoveTo(m_tx, m_ty - ((double)baseline / PANGO_SCALE)); pango_cairo_layout_path(cr, layout); // set bbox and increase current position (m_tx) int lwidth, lheight; pango_layout_get_size(layout, &lwidth, &lheight); double width = ((double)lwidth / PANGO_SCALE); double height = ((double)lheight / PANGO_SCALE); m_char->bbox = wxSVGRect(m_tx, m_ty, width, height); if (style.GetTextAnchor() == wxCSS_VALUE_MIDDLE || style.GetTextAnchor() == wxCSS_VALUE_END) { wxSVGRect bbox = m_char->path->GetResultBBox(style); m_tx += width > bbox.GetWidth() ? width : bbox.GetWidth(); } else m_tx += width; g_object_unref(layout); pango_font_description_free(font); #endif }