void ImageBufferData::transformColorSpace(const Vector<int>& lookUpTable) { ASSERT(m_surface); VGint width = m_surface->width(); VGint height = m_surface->height(); VGubyte* data = new VGubyte[width * height * 4]; VGubyte* currentPixel = data; m_surface->makeCurrent(); vgReadPixels(data, width * 4, IMAGEBUFFER_VG_EXCHANGE_FORMAT, 0, 0, width, height); ASSERT_VG_NO_ERROR(); for (int y = 0; y < height; y++) { for (int x = 0; x < width; currentPixel += 4, x++) { currentPixel[IMAGEBUFFER_A] = lookUpTable[currentPixel[IMAGEBUFFER_A]]; currentPixel[IMAGEBUFFER_R] = lookUpTable[currentPixel[IMAGEBUFFER_R]]; currentPixel[IMAGEBUFFER_G] = lookUpTable[currentPixel[IMAGEBUFFER_G]]; currentPixel[IMAGEBUFFER_B] = lookUpTable[currentPixel[IMAGEBUFFER_B]]; } } vgWritePixels(data, width * 4, IMAGEBUFFER_VG_EXCHANGE_FORMAT, 0, 0, width, height); ASSERT_VG_NO_ERROR(); delete[] data; }
void PainterOpenVG::drawEllipse(const IntRect& rect, VGbitfield specifiedPaintModes) { ASSERT(m_state); VGbitfield paintModes = 0; if (!m_state->strokeDisabled()) paintModes |= VG_STROKE_PATH; if (!m_state->fillDisabled()) paintModes |= VG_FILL_PATH; paintModes &= specifiedPaintModes; if (!paintModes) return; m_surface->makeCurrent(); VGPath path = vgCreatePath( VG_PATH_FORMAT_STANDARD, VG_PATH_DATATYPE_F, 1.0 /* scale */, 0.0 /* bias */, 4 /* expected number of segments */, 12 /* expected number of total coordinates */, VG_PATH_CAPABILITY_APPEND_TO); ASSERT_VG_NO_ERROR(); if (vguEllipse(path, rect.x() + rect.width() / 2.0, rect.y() + rect.height() / 2.0, rect.width(), rect.height()) == VGU_NO_ERROR) { vgDrawPath(path, paintModes); ASSERT_VG_NO_ERROR(); } vgDestroyPath(path); ASSERT_VG_NO_ERROR(); }
void TiledImageOpenVG::detachTiles() { makeSharedContextCurrent(); // because we create new images int numTiles = m_tiles.size(); VGImage newTile, originalTile; for (int i = 0; i < numTiles; ++i) { originalTile = m_tiles.at(i); if (originalTile == VG_INVALID_HANDLE) continue; VGImageFormat format = (VGImageFormat) vgGetParameteri(originalTile, VG_IMAGE_FORMAT); VGint width = vgGetParameteri(originalTile, VG_IMAGE_WIDTH); VGint height = vgGetParameteri(originalTile, VG_IMAGE_HEIGHT); ASSERT_VG_NO_ERROR(); newTile = vgCreateImage(format, width, height, VG_IMAGE_QUALITY_FASTER); ASSERT_VG_NO_ERROR(); vgCopyImage(newTile, 0, 0, originalTile, 0, 0, width, height, VG_FALSE /* dither */); ASSERT_VG_NO_ERROR(); m_tiles.at(i) = newTile; } }
void PainterOpenVG::drawLine(const IntPoint& from, const IntPoint& to) { ASSERT(m_state); if (m_state->strokeDisabled()) return; m_surface->makeCurrent(); VGPath path = vgCreatePath( VG_PATH_FORMAT_STANDARD, VG_PATH_DATATYPE_F, 1.0 /* scale */, 0.0 /* bias */, 2 /* expected number of segments */, 4 /* expected number of total coordinates */, VG_PATH_CAPABILITY_APPEND_TO); ASSERT_VG_NO_ERROR(); VGUErrorCode errorCode; // Try to align lines to pixels, centering them between pixels for odd thickness values. if (fmod(m_state->strokeThickness + 0.5, 2.0) < 1.0) errorCode = vguLine(path, from.x(), from.y(), to.x(), to.y()); else if ((to.y() - from.y()) > (to.x() - from.x())) // more vertical than horizontal errorCode = vguLine(path, from.x() + 0.5, from.y(), to.x() + 0.5, to.y()); else errorCode = vguLine(path, from.x(), from.y() + 0.5, to.x(), to.y() + 0.5); if (errorCode == VGU_NO_ERROR) { vgDrawPath(path, VG_STROKE_PATH); ASSERT_VG_NO_ERROR(); } vgDestroyPath(path); ASSERT_VG_NO_ERROR(); }
NativeImagePtr RGBA32Buffer::asNewNativeImage() const { if (!m_image) { static const VGImageFormat bufferFormat = VG_sARGB_8888_PRE; // Save memory by using 16-bit images for fully opaque images. const VGImageFormat imageFormat = hasAlpha() ? WEBKIT_OPENVG_NATIVE_IMAGE_FORMAT_s_8888 : VG_sRGB_565; #if PLATFORM(EGL) EGLDisplayOpenVG::current()->sharedPlatformSurface()->makeCurrent(); #endif const IntSize vgMaxImageSize(vgGeti(VG_MAX_IMAGE_WIDTH), vgGeti(VG_MAX_IMAGE_HEIGHT)); ASSERT_VG_NO_ERROR(); PassRefPtr<TiledImageOpenVG> tiledImage = adoptRef(new TiledImageOpenVG( IntSize(width(), height()), vgMaxImageSize)); const int numColumns = tiledImage->numColumns(); const int numRows = tiledImage->numRows(); for (int yIndex = 0; yIndex < numRows; ++yIndex) { for (int xIndex = 0; xIndex < numColumns; ++xIndex) { IntRect tileRect = tiledImage->tileRect(xIndex, yIndex); VGImage tile = vgCreateImage(imageFormat, tileRect.width(), tileRect.height(), VG_IMAGE_QUALITY_FASTER); ASSERT_VG_NO_ERROR(); PixelData* pixelData = m_bytes.data(); pixelData += (tileRect.y() * width()) + tileRect.x(); vgImageSubData(tile, reinterpret_cast<unsigned char*>(pixelData), width() * sizeof(PixelData), bufferFormat, 0, 0, tileRect.width(), tileRect.height()); ASSERT_VG_NO_ERROR(); tiledImage->setTile(xIndex, yIndex, tile); } } // Incomplete images will be returned without storing them in m_image, // so the image will be regenerated once loading is complete. if (m_status != FrameComplete) return tiledImage; m_image = tiledImage; m_bytes.clear(); } return m_image; // and increase refcount }
VGPath SurfaceOpenVG::cachedPath(CachedPathDescriptor which) { Vector<VGPath>& paths = cachedPaths(); if (paths.isEmpty()) { paths.resize(CachedPathCount); paths.fill(VG_INVALID_HANDLE); } if (paths.at(which) == VG_INVALID_HANDLE) { sharedSurface()->makeCurrent(); VGPath path = VG_INVALID_HANDLE; VGUErrorCode errorCode; switch (which) { case CachedLinePath: path = vgCreatePath( VG_PATH_FORMAT_STANDARD, VG_PATH_DATATYPE_F, 1.0 /* scale */, 0.0 /* bias */, 2 /* expected number of segments */, 4 /* expected number of total coordinates */, VG_PATH_CAPABILITY_APPEND_TO); ASSERT_VG_NO_ERROR(); errorCode = vguLine(path, 0, 0, 1, 0); ASSERT(errorCode == VGU_NO_ERROR); break; case CachedRectPath: path = vgCreatePath( VG_PATH_FORMAT_STANDARD, VG_PATH_DATATYPE_F, 1.0 /* scale */, 0.0 /* bias */, 5 /* expected number of segments */, 5 /* expected number of total coordinates */, VG_PATH_CAPABILITY_APPEND_TO); ASSERT_VG_NO_ERROR(); errorCode = vguRect(path, 0, 0, 1, 1); ASSERT(errorCode == VGU_NO_ERROR); break; default: ASSERT_NOT_REACHED(); } paths.at(which) = path; makeCurrent(); } return paths.at(which); }
void applyStrokeStyle() { if (strokeStyle == DottedStroke) { VGfloat vgFloatArray[2] = { 1.0, 1.0 }; vgSetfv(VG_STROKE_DASH_PATTERN, 2, vgFloatArray); vgSetf(VG_STROKE_DASH_PHASE, 0.0); } else if (strokeStyle == DashedStroke) { if (!strokeDashArray.size()) { VGfloat vgFloatArray[2] = { 4.0, 3.0 }; vgSetfv(VG_STROKE_DASH_PATTERN, 2, vgFloatArray); } else { Vector<VGfloat> vgFloatArray(strokeDashArray.size()); for (int i = 0; i < strokeDashArray.size(); ++i) vgFloatArray[i] = strokeDashArray[i]; vgSetfv(VG_STROKE_DASH_PATTERN, vgFloatArray.size(), vgFloatArray.data()); } vgSetf(VG_STROKE_DASH_PHASE, strokeDashOffset); } else { vgSetfv(VG_STROKE_DASH_PATTERN, 0, 0); vgSetf(VG_STROKE_DASH_PHASE, 0.0); } ASSERT_VG_NO_ERROR(); }
void ImageBufferData::putImageData(ImageData*& source, const IntRect& sourceRect, const IntPoint& destPoint, const IntSize& size, VGImageFormat format) { ASSERT(m_surface); ASSERT(sourceRect.width() > 0); ASSERT(sourceRect.height() > 0); // We expect the sourceRect to be a subset of the given source image. ASSERT(sourceRect.x() >= 0); ASSERT(sourceRect.y() >= 0); ASSERT(sourceRect.right() <= source->width()); ASSERT(sourceRect.bottom() <= source->height()); // The target origin point is the combined offset of sourceRect.location() // and destPoint. int destx = destPoint.x() + sourceRect.x(); int desty = destPoint.y() + sourceRect.y(); ASSERT(destx >= 0); ASSERT(desty >= 0); ASSERT(destx + sourceRect.width() <= size.width()); ASSERT(desty + sourceRect.height() <= size.height()); unsigned const char* data = source->data()->data()->data(); int dataOffset = (sourceRect.y() * source->width() * 4) + (sourceRect.x() * 4); m_surface->makeCurrent(); vgWritePixels(data + dataOffset, source->width() * 4, format, destx, desty, sourceRect.width(), sourceRect.height()); ASSERT_VG_NO_ERROR(); }
PlatformPathOpenVG::~PlatformPathOpenVG() { makeCompatibleContextCurrent(); vgDestroyPath(m_vgPath); ASSERT_VG_NO_ERROR(); }
float Path::length() { m_path->makeCompatibleContextCurrent(); VGfloat length = vgPathLength(m_path->vgPath(), 0, vgGetParameteri(m_path->vgPath(), VG_PATH_NUM_SEGMENTS)); ASSERT_VG_NO_ERROR(); return length; }
PassRefPtr<ImageData> ImageBufferData::getImageData(const IntRect& rect, const IntSize& size, VGImageFormat format) const { ASSERT(m_surface); PassRefPtr<ImageData> result = ImageData::create(rect.width(), rect.height()); unsigned char* data = result->data()->data()->data(); // If this copy operation won't fill all of the pixels in the target image, // paint it black in order to avoid random uninitialized pixel garbage. if (rect.x() < 0 || rect.y() < 0 || (rect.right()) > size.width() || (rect.bottom()) > size.height()) memset(data, 0, result->data()->length()); if (!m_tiledImage) m_surface->makeCurrent(); // OpenVG ignores pixels that are out of bounds, so we can just // call vgReadPixels() without any further safety assurances. if (m_surface->isCurrent()) { vgReadPixels(data, rect.width() * 4, format, rect.x(), rect.y(), rect.width(), rect.height()); } else { vgGetImageSubData(m_tiledImage->tile(0, 0), data, rect.width() * 4, format, rect.x(), rect.y(), rect.width(), rect.height()); } ASSERT_VG_NO_ERROR(); return result; }
void Path::addArcTo(const FloatPoint& point1, const FloatPoint& point2, float radius) { // See http://philip.html5.org/tests/canvas/suite/tests/spec.html#arcto. const FloatPoint& point0 = m_path->m_currentPoint; if (!radius || point0 == point1 || point1 == point2) { addLineTo(point1); return; } FloatSize v01 = point0 - point1; FloatSize v21 = point2 - point1; // sin(A - B) = sin(A) * cos(B) - sin(B) * cos(A) double cross = v01.width() * v21.height() - v01.height() * v21.width(); if (fabs(cross) < 1E-10) { // on one line addLineTo(point1); return; } double d01 = hypot(v01.width(), v01.height()); double d21 = hypot(v21.width(), v21.height()); double angle = (piDouble - fabs(asin(cross / (d01 * d21)))) * 0.5; double span = radius * tan(angle); double rate = span / d01; FloatPoint startPoint = FloatPoint(point1.x() + v01.width() * rate, point1.y() + v01.height() * rate); rate = span / d21; FloatPoint endPoint = FloatPoint(point1.x() + v21.width() * rate, point1.y() + v21.height() * rate); // Fa: large arc flag, makes the difference between SCWARC_TO and LCWARC_TO // respectively SCCWARC_TO and LCCWARC_TO arcs. We always use small // arcs for arcTo(), as the arc is defined as the "shortest arc" of the // circle specified in HTML 5. // Fs: sweep flag, specifying whether the arc is drawn in increasing (true) // or decreasing (0) direction. const bool anticlockwise = cross < 0; // Translate the large arc and sweep flags into an OpenVG segment command. const VGubyte segmentCommand = anticlockwise ? VG_SCCWARC_TO_ABS : VG_SCWARC_TO_ABS; const VGubyte pathSegments[] = { VG_LINE_TO_ABS, segmentCommand }; const VGfloat pathData[] = { startPoint.x(), startPoint.y(), radius, radius, 0, endPoint.x(), endPoint.y() }; m_path->makeCompatibleContextCurrent(); vgAppendPathData(m_path->vgPath(), 2, pathSegments, pathData); ASSERT_VG_NO_ERROR(); m_path->m_currentPoint = endPoint; }
static void setVGSolidColor(VGPaintMode paintMode, const Color& color) { VGPaint paint = vgCreatePaint(); vgSetParameteri(paint, VG_PAINT_TYPE, VG_PAINT_TYPE_COLOR); vgSetColor(paint, colorToVGColor(color)); vgSetPaint(paint, paintMode); vgDestroyPaint(paint); ASSERT_VG_NO_ERROR(); }
void PainterOpenVG::setStrokeThickness(float thickness) { ASSERT(m_state); m_surface->makeCurrent(); m_state->strokeThickness = thickness; vgSetf(VG_STROKE_LINE_WIDTH, thickness); ASSERT_VG_NO_ERROR(); }
void PainterOpenVG::setLineCap(LineCap lineCap) { ASSERT(m_state); m_surface->makeCurrent(); m_state->strokeLineCap = lineCap; vgSeti(VG_STROKE_CAP_STYLE, toVGCapStyle(lineCap)); ASSERT_VG_NO_ERROR(); }
void PainterOpenVG::setLineJoin(LineJoin lineJoin) { ASSERT(m_state); m_surface->makeCurrent(); m_state->strokeLineJoin = lineJoin; vgSeti(VG_STROKE_JOIN_STYLE, toVGJoinStyle(lineJoin)); ASSERT_VG_NO_ERROR(); }
void PainterOpenVG::setMiterLimit(float miterLimit) { ASSERT(m_state); m_surface->makeCurrent(); m_state->strokeMiterLimit = miterLimit; vgSetf(VG_STROKE_MITER_LIMIT, miterLimit); ASSERT_VG_NO_ERROR(); }
void PainterOpenVG::drawPolygon(size_t numPoints, const FloatPoint* points, VGbitfield specifiedPaintModes) { ASSERT(m_state); VGbitfield paintModes = 0; if (!m_state->strokeDisabled()) paintModes |= VG_STROKE_PATH; if (!m_state->fillDisabled()) paintModes |= VG_FILL_PATH; paintModes &= specifiedPaintModes; if (!paintModes) return; m_surface->makeCurrent(); // Path segments: all points + "close path". const VGint numSegments = numPoints + 1; const VGint numCoordinates = numPoints * 2; VGPath path = vgCreatePath( VG_PATH_FORMAT_STANDARD, VG_PATH_DATATYPE_F, 1.0 /* scale */, 0.0 /* bias */, numSegments /* expected number of segments */, numCoordinates /* expected number of total coordinates */, VG_PATH_CAPABILITY_APPEND_TO); ASSERT_VG_NO_ERROR(); Vector<VGfloat> vgPoints(numCoordinates); for (int i = 0; i < numPoints; ++i) { vgPoints[i*2] = points[i].x(); vgPoints[i*2 + 1] = points[i].y(); } if (vguPolygon(path, vgPoints.data(), numPoints, VG_TRUE /* closed */) == VGU_NO_ERROR) { vgDrawPath(path, paintModes); ASSERT_VG_NO_ERROR(); } vgDestroyPath(path); ASSERT_VG_NO_ERROR(); }
void applyScissorRect() { if (scissoringEnabled) { vgSeti(VG_SCISSORING, VG_TRUE); vgSetfv(VG_SCISSOR_RECTS, 4, VGRect(scissorRect).toVGfloat()); } else vgSeti(VG_SCISSORING, VG_FALSE); ASSERT_VG_NO_ERROR(); }
PlatformPathOpenVG& PlatformPathOpenVG::operator=(const PlatformPathOpenVG& other) { if (&other != this) { clear(); // makeCompatibleContextCurrent() is called by clear(), so not necessary here. vgAppendPath(m_vgPath, other.m_vgPath); ASSERT_VG_NO_ERROR(); } return *this; }
PlatformPathOpenVG::PlatformPathOpenVG(const PlatformPathOpenVG& other) : SharedResourceOpenVG() , m_currentPoint(other.m_currentPoint) , m_subpathStartPoint(other.m_subpathStartPoint) { createPath(); // makeCompatibleContextCurrent() is called by createPath(), so not necessary here. vgAppendPath(m_vgPath, other.m_vgPath); ASSERT_VG_NO_ERROR(); }
void PlatformPathOpenVG::clear() { makeCompatibleContextCurrent(); vgClearPath(m_vgPath, WEBKIT_VG_PATH_CAPABILITIES); ASSERT_VG_NO_ERROR(); m_subpathStartPoint.setX(0); m_subpathStartPoint.setY(0); m_currentPoint = m_subpathStartPoint; }
void Path::addBezierCurveTo(const FloatPoint& controlPoint1, const FloatPoint& controlPoint2, const FloatPoint& endPoint) { static const VGubyte pathSegments[] = { VG_CUBIC_TO_ABS }; const VGfloat pathData[] = { controlPoint1.x(), controlPoint1.y(), controlPoint2.x(), controlPoint2.y(), endPoint.x(), endPoint.y() }; m_path->makeCompatibleContextCurrent(); vgAppendPathData(m_path->vgPath(), 1, pathSegments, pathData); ASSERT_VG_NO_ERROR(); m_path->m_currentPoint = endPoint; }
void Path::addLineTo(const FloatPoint& point) { static const VGubyte pathSegments[] = { VG_LINE_TO_ABS }; const VGfloat pathData[] = { point.x(), point.y() }; m_path->makeCompatibleContextCurrent(); vgAppendPathData(m_path->vgPath(), 1, pathSegments, pathData); ASSERT_VG_NO_ERROR(); m_path->m_currentPoint = point; }
void PlatformPathOpenVG::createPath() { makeResourceCreationContextCurrent(); m_vgPath = vgCreatePath( VG_PATH_FORMAT_STANDARD, VG_PATH_DATATYPE_F, 1.0 /* scale */, 0.0 /* bias */, 0 /* expected number of segments */, 0 /* expected number of total coordinates */, WEBKIT_VG_PATH_CAPABILITIES); ASSERT_VG_NO_ERROR(); }
NativeImagePtr RGBA32Buffer::asNewNativeImage() const { static const VGImageFormat bufferFormat = VG_sARGB_8888_PRE; // Save memory by using 16-bit images for fully opaque images. const VGImageFormat imageFormat = hasAlpha() ? bufferFormat : VG_sRGB_565; #if PLATFORM(EGL) EGLDisplayOpenVG::current()->sharedPlatformSurface()->makeCurrent(); #endif const IntSize vgMaxImageSize(vgGeti(VG_MAX_IMAGE_WIDTH), vgGeti(VG_MAX_IMAGE_HEIGHT)); ASSERT_VG_NO_ERROR(); TiledImageOpenVG* tiledImage = new TiledImageOpenVG(IntSize(width(), height()), vgMaxImageSize); const int numColumns = tiledImage->numColumns(); const int numRows = tiledImage->numRows(); for (int yIndex = 0; yIndex < numRows; ++yIndex) { for (int xIndex = 0; xIndex < numColumns; ++xIndex) { IntRect tileRect = tiledImage->tileRect(xIndex, yIndex); VGImage image = vgCreateImage(imageFormat, tileRect.width(), tileRect.height(), VG_IMAGE_QUALITY_FASTER); ASSERT_VG_NO_ERROR(); PixelData* pixelData = const_cast<PixelData*>(m_bytes); pixelData += (tileRect.y() * width()) + tileRect.x(); vgImageSubData(image, reinterpret_cast<unsigned char*>(pixelData), width() * sizeof(PixelData), bufferFormat, 0, 0, tileRect.width(), tileRect.height()); ASSERT_VG_NO_ERROR(); tiledImage->setTile(xIndex, yIndex, image); } } return tiledImage; }
FloatRect Path::boundingRect() const { VGfloat minX; VGfloat minY; VGfloat width; VGfloat height; m_path->makeCompatibleContextCurrent(); vgPathBounds(m_path->vgPath(), &minX, &minY, &width, &height); ASSERT_VG_NO_ERROR(); return FloatRect(FloatPoint(minX, minY), FloatSize(width, height)); }
void applyTransformationMatrix(PainterOpenVG* painter) { // There are *five* separate transforms that can be applied to OpenVG as of 1.1 // but it is not clear that we need to set them separately. Instead we set them // all right here and let this be a call to essentially set the world transformation! VGMatrix vgMatrix(surfaceTransformationMatrix); const VGfloat* vgFloatArray = vgMatrix.toVGfloat(); vgSeti(VG_MATRIX_MODE, VG_MATRIX_PATH_USER_TO_SURFACE); vgLoadMatrix(vgFloatArray); ASSERT_VG_NO_ERROR(); vgSeti(VG_MATRIX_MODE, VG_MATRIX_IMAGE_USER_TO_SURFACE); vgLoadMatrix(vgFloatArray); ASSERT_VG_NO_ERROR(); #ifdef OPENVG_VERSION_1_1 vgSeti(VG_MATRIX_MODE, VG_MATRIX_GLYPH_USER_TO_SURFACE); vgLoadMatrix(vgFloatArray); ASSERT_VG_NO_ERROR(); #endif }
FloatRect Font::selectionRectForComplexText(const TextRun& run, const FloatPoint& point, int height, int from, int to, int width) const { const FontPlatformData& fontPlatformData = primaryFont()->platformData(); const float scaleFactor = fontPlatformData.scaleFactor(); Olympia::Platform::Text::Font* font = fontPlatformData.font(); Olympia::Platform::Text::DrawParam drawParam; String sanitized = setupTextDrawing(this, run, &drawParam); adjustOffsetsForTextDrawing(run, from, to); #if PLATFORM(EGL) // FIXME: remove after Text API fixes shared context handling if (eglGetCurrentContext() == EGL_NO_CONTEXT) EGLDisplayOpenVG::current()->sharedPlatformSurface()->makeCurrent(); #endif double fromX; FontPlatformData::engine()->textPosToX(from, fromX, *font, sanitized.characters(), sanitized.length(), drawParam); ASSERT_VG_NO_ERROR(); fromX *= scaleFactor; double toX; FontPlatformData::engine()->textPosToX(to, toX, *font, sanitized.characters(), sanitized.length(), drawParam); ASSERT_VG_NO_ERROR(); toX *= scaleFactor; if (width) { double bound = width * scaleFactor; if (from == run.length()) fromX = bound; if (to == run.length()) toX = bound; } return (toX > fromX) ? FloatRect(point.x() + fromX, point.y(), toX - fromX, height) : FloatRect(point.x() + toX, point.y(), fromX - toX, height); }
void Path::closeSubpath() { static const VGubyte pathSegments[] = { VG_CLOSE_PATH }; // pathData must not be 0, but certain compilers also don't create // zero-size arrays. So let's use a random aligned value (sizeof(VGfloat)), // it won't be accessed anyways as VG_CLOSE_PATH doesn't take coordinates. static const VGfloat* pathData = reinterpret_cast<VGfloat*>(sizeof(VGfloat)); m_path->makeCompatibleContextCurrent(); vgAppendPathData(m_path->vgPath(), 1, pathSegments, pathData); ASSERT_VG_NO_ERROR(); m_path->m_currentPoint = m_path->m_subpathStartPoint; }