コード例 #1
0
ファイル: SampleFatBits.cpp プロジェクト: Jichao/skia
void FatBits::drawLineSkeleton(SkCanvas* max, const SkPoint pts[]) {
    SkPaint paint;
    this->setupSkeletonPaint(&paint);

    SkPath path;
    path.moveTo(pts[0]);
    path.lineTo(pts[1]);

    switch (fStyle) {
        case kHair_Style:
            if (fUseGPU) {
                SkPaint p;
                p.setStyle(SkPaint::kStroke_Style);
                p.setStrokeWidth(SK_Scalar1 * fZoom);
                SkPath dst;
                p.getFillPath(path, &dst);
                path.addPath(dst);
            }
            break;
        case kStroke_Style: {
            SkPaint p;
            p.setStyle(SkPaint::kStroke_Style);
            p.setStrokeWidth(SK_Scalar1 * fZoom);
            SkPath dst;
            p.getFillPath(path, &dst);
            path = dst;

            if (fUseGPU) {
                path.moveTo(dst.getPoint(0));
                path.lineTo(dst.getPoint(2));
            }
        } break;
    }
    max->drawPath(path, paint);
}
コード例 #2
0
ファイル: SampleStrokeText.cpp プロジェクト: bunhere/skia
static void lettersToBitmap2(SkBitmap* dst, const char chars[],
                            const SkPaint& original, SkBitmap::Config config) {
    SkPath path;
    SkScalar x = 0;
    SkScalar width;
    SkPath p;
    for (size_t i = 0; i < strlen(chars); i++) {
        original.getTextPath(&chars[i], 1, x, 0, &p);
        path.addPath(p);
        original.getTextWidths(&chars[i], 1, &width);
        x += width;
    }
    SkRect bounds = path.getBounds();
    SkScalar sw = -original.getStrokeWidth();
    bounds.inset(sw, sw);
    path.offset(-bounds.fLeft, -bounds.fTop);
    bounds.offset(-bounds.fLeft, -bounds.fTop);

    int w = SkScalarRound(bounds.width());
    int h = SkScalarRound(bounds.height());
    SkPaint paint(original);

    paint.setAntiAlias(true);
    paint.setXfermodeMode(SkXfermode::kDstATop_Mode);
    paint.setColor(original.getColor());
    paint.setStyle(SkPaint::kStroke_Style);

    dst->setConfig(config, w, h);
    dst->allocPixels();
    dst->eraseColor(SK_ColorWHITE);

    SkCanvas canvas(*dst);
    canvas.drawPath(path, paint);
}
コード例 #3
0
// Draws the given text string using skia.  Note that gradient or
// pattern may be NULL, in which case a solid colour is used.
static bool skiaDrawText(HFONT hfont,
                         HDC dc,
                         SkCanvas* canvas,
                         const SkPoint& point,
                         SkPaint* paint,
                         const WORD* glyphs,
                         const int* advances,
                         const GOFFSET* offsets,
                         int numGlyphs)
{
    float x = point.fX, y = point.fY;

    for (int i = 0; i < numGlyphs; i++) {
        const SkPath* path = SkiaWinOutlineCache::lookupOrCreatePathForGlyph(dc, hfont, glyphs[i]);
        if (!path)
            return false;

        float offsetX = 0.0f, offsetY = 0.0f;
        if (offsets && (offsets[i].du != 0 || offsets[i].dv != 0)) {
            offsetX = offsets[i].du;
            offsetY = offsets[i].dv;
        }

        SkPath newPath;
        newPath.addPath(*path, x + offsetX, y + offsetY);
        canvas->drawPath(newPath, *paint);

        x += advances[i];
    }

    return true;
}
コード例 #4
0
static bool innerPathOp(skiatest::Reporter* reporter, const SkPath& a, const SkPath& b,
                 const SkPathOp shapeOp, const char* testName, bool threaded) {
#if DEBUG_SHOW_TEST_NAME
    if (testName == NULL) {
        SkDebugf("\n");
        showPathData(a);
        showOp(shapeOp);
        showPathData(b);
    } else {
        SkPathOpsDebug::ShowPath(a, b, shapeOp, testName);
    }
#endif
    SkPath out;
    if (!Op(a, b, shapeOp, &out) ) {
        SkDebugf("%s did not expect failure\n", __FUNCTION__);
        REPORTER_ASSERT(reporter, 0);
        return false;
    }
    if (threaded && !reporter->verbose()) {
        return true;
    }
    SkPath pathOut, scaledPathOut;
    SkRegion rgnA, rgnB, openClip, rgnOut;
    openClip.setRect(-16000, -16000, 16000, 16000);
    rgnA.setPath(a, openClip);
    rgnB.setPath(b, openClip);
    rgnOut.op(rgnA, rgnB, (SkRegion::Op) shapeOp);
    rgnOut.getBoundaryPath(&pathOut);

    SkMatrix scale;
    scaleMatrix(a, b, scale);
    SkRegion scaledRgnA, scaledRgnB, scaledRgnOut;
    SkPath scaledA, scaledB;
    scaledA.addPath(a, scale);
    scaledA.setFillType(a.getFillType());
    scaledB.addPath(b, scale);
    scaledB.setFillType(b.getFillType());
    scaledRgnA.setPath(scaledA, openClip);
    scaledRgnB.setPath(scaledB, openClip);
    scaledRgnOut.op(scaledRgnA, scaledRgnB, (SkRegion::Op) shapeOp);
    scaledRgnOut.getBoundaryPath(&scaledPathOut);
    SkBitmap bitmap;
    SkPath scaledOut;
    scaledOut.addPath(out, scale);
    scaledOut.setFillType(out.getFillType());
    int result = comparePaths(reporter, pathOut, scaledPathOut, out, scaledOut, bitmap, a, b,
                              shapeOp, scale);
    if (result && gPathStrAssert) {
        REPORTER_ASSERT(reporter, 0);
    }
    reporter->bumpTestCount();
    return result == 0;
}
コード例 #5
0
ファイル: PathOpsExtendedTest.cpp プロジェクト: ericrk/skia
static bool innerPathOp(skiatest::Reporter* reporter, const SkPath& a, const SkPath& b,
        const SkPathOp shapeOp, const char* testName, ExpectSuccess expectSuccess,
        SkipAssert skipAssert, ExpectMatch expectMatch) {
#if 0 && DEBUG_SHOW_TEST_NAME
    showName(a, b, shapeOp);
#endif
    SkPath out;
    if (!OpDebug(a, b, shapeOp, &out  SkDEBUGPARAMS(SkipAssert::kYes == skipAssert)
            SkDEBUGPARAMS(testName))) {
        if (ExpectSuccess::kYes == expectSuccess) {
            SkDebugf("%s %s did not expect failure\n", __FUNCTION__, testName);
            REPORTER_ASSERT(reporter, 0);
        }
        return false;
    } else {
        if (ExpectSuccess::kNo == expectSuccess) {
                SkDebugf("%s %s unexpected success\n", __FUNCTION__, testName);
                REPORTER_ASSERT(reporter, 0);
        }
    }
    if (!reporter->verbose()) {
        return true;
    }
    SkPath pathOut, scaledPathOut;
    SkRegion rgnA, rgnB, openClip, rgnOut;
    openClip.setRect(-16000, -16000, 16000, 16000);
    rgnA.setPath(a, openClip);
    rgnB.setPath(b, openClip);
    rgnOut.op(rgnA, rgnB, (SkRegion::Op) shapeOp);
    rgnOut.getBoundaryPath(&pathOut);

    SkMatrix scale;
    scaleMatrix(a, b, scale);
    SkRegion scaledRgnA, scaledRgnB, scaledRgnOut;
    SkPath scaledA, scaledB;
    scaledA.addPath(a, scale);
    scaledA.setFillType(a.getFillType());
    scaledB.addPath(b, scale);
    scaledB.setFillType(b.getFillType());
    scaledRgnA.setPath(scaledA, openClip);
    scaledRgnB.setPath(scaledB, openClip);
    scaledRgnOut.op(scaledRgnA, scaledRgnB, (SkRegion::Op) shapeOp);
    scaledRgnOut.getBoundaryPath(&scaledPathOut);
    SkBitmap bitmap;
    SkPath scaledOut;
    scaledOut.addPath(out, scale);
    scaledOut.setFillType(out.getFillType());
    int result = comparePaths(reporter, testName, pathOut, scaledPathOut, out, scaledOut, bitmap,
            a, b, shapeOp, scale, ExpectMatch::kYes == expectMatch);
    reporter->bumpTestCount();
    return result == 0;
}
コード例 #6
0
static void
_update_path(mbe_t *mbe) {
    SkPath *path = mbe->path;
    SkPath *subpath = mbe->subpath;
    SkMatrix canvas_matrix;
    SkPoint point;

    MB_MATRIX_2_SKMATRIX(canvas_matrix, mbe->states->matrix);
    path->addPath(*subpath, canvas_matrix);

    subpath->getLastPt(&point);
    subpath->rewind();
    subpath->moveTo(point);
}
コード例 #7
0
void Path::addArc(const FloatPoint& p, float r, float sa, float ea,
                  bool clockwise) {
    SkScalar    cx = SkFloatToScalar(p.x());
    SkScalar    cy = SkFloatToScalar(p.y());
    SkScalar    radius = SkFloatToScalar(r);

    SkRect  oval;
    oval.set(cx - radius, cy - radius, cx + radius, cy + radius);
    
    float sweep = ea - sa;
    bool prependOval = false;

    /*  Note if clockwise and the sign of the sweep disagree. This particular
        logic was deduced from http://canvex.lazyilluminati.com/misc/arc.html
    */
    if (clockwise && (sweep > 0 || sweep < -g2PI)) {
        sweep = fmodf(sweep, g2PI) - g2PI;
    } else if (!clockwise && (sweep < 0 || sweep > g2PI)) {
        sweep = fmodf(sweep, g2PI) + g2PI;
    }
    
    // If the abs(sweep) >= 2PI, then we need to add a circle before we call
    // arcTo, since it treats the sweep mod 2PI. We don't have a prepend call,
    // so we just remember this, and at the end create a new path with an oval
    // and our current path, and then swap then.
    //
    if (sweep >= g2PI || sweep <= -g2PI) {
        prependOval = true;
//        SkDebugf("addArc sa=%g ea=%g cw=%d sweep %g treat as circle\n", sa, ea, clockwise, sweep);

        // now reduce sweep to just the amount we need, so that the current
        // point is left where the caller expects it.
        sweep = fmodf(sweep, g2PI);
    }

    sa = fast_mod(sa, g2PI);
    SkScalar startDegrees = SkFloatToScalar(sa * g180OverPI);
    SkScalar sweepDegrees = SkFloatToScalar(sweep * g180OverPI);

//    SkDebugf("addArc sa=%g ea=%g cw=%d sweep=%g ssweep=%g\n", sa, ea, clockwise, sweep, SkScalarToFloat(sweepDegrees));
    m_path->arcTo(oval, startDegrees, sweepDegrees, false);
    
    if (prependOval) {
        SkPath tmp;
        tmp.addOval(oval);
        tmp.addPath(*m_path);
        m_path->swap(tmp);
    }
}
コード例 #8
0
void mbe_arc(mbe_t *mbe, co_aix x, co_aix y, co_aix radius,
		    co_aix angle_start, co_aix angle_stop) {
    SkPoint point;
    SkPath *subpath = mbe->subpath;
    SkRect rect;
    SkScalar x0, y0;
    SkScalar ang_start, ang_stop;
    SkScalar sweep;
    SkScalar r;			/* radius */

    subpath->getLastPt(&point);
    x0 = point.fX;
    y0 = point.fX;
    r = CO_AIX_2_SKSCALAR(radius);
    ang_start = CO_AIX_2_SKSCALAR(angle_start * 180 / PI);
    ang_stop = CO_AIX_2_SKSCALAR(angle_stop * 180 / PI);

    /* Skia can only draw an arc in clockwise directly.  We negative
     * start and stop point to draw the arc in the mirror along x-axis
     * in a sub-path.  Then, the sub-path are reflected along x-axis,
     * again.  We get a right path, and add it to the path of mbe_t.
     */
    if(ang_start > ang_stop) {
	SkPath tmppath;
	SkMatrix matrix;
	co_aix reflect[6] = { 1, 0, 0,
			      0, -1, 0};

	rect.set(-r, -r, r, r);
	sweep = ang_start - ang_stop;
	tmppath.arcTo(rect, -ang_start, sweep, false);

	reflect[2] = x;
	reflect[5] = y;
	MB_MATRIX_2_SKMATRIX(matrix, reflect);
	subpath->addPath(tmppath, matrix);
    } else {
	rect.set(x0 - r, y0 - r, x0 + r, y0 + r);
	sweep = ang_stop - ang_start;
	subpath->arcTo(rect, ang_start, sweep, false);
    }
}
コード例 #9
0
ファイル: EnvelopeWarp.cpp プロジェクト: develvic/textart
void TextArt::EnvelopeWarp::morph(SkPath& bSkeleton, SkPathMeasure& bMeasure, SkPathCrossing& bCrossing,
								SkPath& tSkeleton, SkPathMeasure& tMeasure, SkPathCrossing& tCrossing,
								SkPath& glypthPath, SkPathMeasure& lineMeasure, SkMatrix& scaleMatrix,
								SkScalar xpos, SkScalar hBOffset, SkScalar hTOffset, SkPath& warpedPath)
{
	SkRect glypthBound;
	glypthBound = glypthPath.getBounds();

	SkScalar k1 = 1.0;

	if (!isSymmetric_)
	{	
		SkScalar hBOffsetTmp = 0.0;
		SkScalar hTOffsetTmp = 0.0;

		if (isTopBased_)
		{
			glypthBound.fTop = 0;
			glypthBound.fBottom = -boundsRect_.height();

			SkMatrix	compositeTMatrix(scaleMatrix);
			compositeTMatrix.postTranslate(xpos + hTOffset, 0);
			compositeTMatrix.postConcat(matrix_);

			if ( getK(glypthBound, bCrossing, tCrossing, tMeasure, compositeTMatrix, k1, hBOffsetTmp, hTOffsetTmp) )
			{
				k1 = 1/k1;

				hBOffset = hBOffsetTmp;
				hTOffset = xpos + hTOffset;
			}
		}
		else
		{
			glypthBound.fTop = -boundsRect_.height();
			glypthBound.fBottom = 0;

			SkMatrix	compositeBMatrix(scaleMatrix);
			compositeBMatrix.postTranslate(xpos + hBOffset, 0);
			compositeBMatrix.postConcat(matrix_);

			if ( getK(glypthBound, bCrossing, tCrossing, bMeasure, compositeBMatrix, k1, hBOffsetTmp, hTOffsetTmp) )
			{
				//use distance to Left on Top Skeleton for positioning Top glypthn
				hTOffset = hTOffsetTmp;
				hBOffset = xpos + hBOffset;
			}
		}
	}
	else
	{
		hBOffset = xpos + hBOffset;
		hTOffset = hBOffset;
	}
				
	SkMatrix	compositeBMatrix(scaleMatrix);
	compositeBMatrix.postTranslate(hBOffset, 0);
	compositeBMatrix.postConcat(matrix_);

	//warp Glypth by bottom line
	k1_ = isTopBased_ ? k1 : SkIntToScalar(1);
	isTop = false;
	SkPath bWarped;
	morphpath(&bWarped, glypthPath, bMeasure, compositeBMatrix);
	bWarped_.addPath(bWarped);

	if (!tSkeleton_.isEmpty())
	{
		SkMatrix	compositeTMatrix(scaleMatrix);
		compositeTMatrix.postTranslate(hTOffset, 0);
		compositeTMatrix.postConcat(matrix_);

		//warp Glypth by top line
		k1_ = !isTopBased_ ? k1 : SkIntToScalar(1);
		isTop = true;
		SkPath tWarped;
		morphpath(&tWarped, glypthPath, tMeasure, compositeTMatrix);
		tWarped_.addPath(tWarped);

		//convert Glypth to Path to allow weighting
		SkPath lineMorphed;
		morphpath(&lineMorphed, glypthPath, lineMeasure, scaleMatrix);

		weight(lineMorphed, tWarped, bWarped, &warpedPath);
	}
	else
		warpedPath.addPath(bWarped_);
}
コード例 #10
0
ファイル: SamplePathFuzz.cpp プロジェクト: Arternis/skia
SkPath makePath() {
    SkPath path;
    for (uint32_t cIndex = 0; cIndex < fPathContourCount; ++cIndex) {
        uint32_t segments = makeSegmentCount();
        for (uint32_t sIndex = 0; sIndex < segments; ++sIndex) {
            RandomAddPath addPathType = makeAddPathType();
            ++fAddCount;
            if (fPrintName) {
                SkDebugf("%.*s%s\n", fPathDepth * 3, fTab,
                        gRandomAddPathNames[addPathType]);
            }
            switch (addPathType) {
                case kAddArc: {
                    SkRect oval = makeRect();
                    SkScalar startAngle = makeAngle();
                    SkScalar sweepAngle = makeAngle();
                    path.addArc(oval, startAngle, sweepAngle);
                    validate(path);
                    } break;
                case kAddRoundRect1: {
                    SkRect rect = makeRect();
                    SkScalar rx = makeScalar(), ry = makeScalar();
                    SkPath::Direction dir = makeDirection();
                    path.addRoundRect(rect, rx, ry, dir);
                    validate(path);
                    } break;
                case kAddRoundRect2: {
                    SkRect rect = makeRect();
                    SkScalar radii[8];
                    makeScalarArray(SK_ARRAY_COUNT(radii), radii);
                    SkPath::Direction dir = makeDirection();
                    path.addRoundRect(rect, radii, dir);
                    validate(path);
                    } break;
                case kAddRRect: {
                    SkRRect rrect = makeRRect();
                    SkPath::Direction dir = makeDirection();
                    path.addRRect(rrect, dir);
                    validate(path);
                    } break;
                case kAddPoly: {
                    SkTDArray<SkPoint> points;
                    makePointArray(&points);
                    bool close = makeBool();
                    path.addPoly(&points[0], points.count(), close);
                    validate(path);
                    } break;
                case kAddPath1:
                    if (fPathDepth < fPathDepthLimit) {
                        ++fPathDepth;
                        SkPath src = makePath();
                        validate(src);
                        SkScalar dx = makeScalar();
                        SkScalar dy = makeScalar();
                        SkPath::AddPathMode mode = makeAddPathMode();
                        path.addPath(src, dx, dy, mode);
                        --fPathDepth;
                        validate(path);
                    }
                    break;
                case kAddPath2:
                    if (fPathDepth < fPathDepthLimit) {
                        ++fPathDepth;
                        SkPath src = makePath();
                        validate(src);
                        SkPath::AddPathMode mode = makeAddPathMode();
                        path.addPath(src, mode);
                        --fPathDepth;
                        validate(path);
                    }
                    break;
                case kAddPath3:
                    if (fPathDepth < fPathDepthLimit) {
                        ++fPathDepth;
                        SkPath src = makePath();
                        validate(src);
                        SkMatrix matrix = makeMatrix();
                        SkPath::AddPathMode mode = makeAddPathMode();
                        path.addPath(src, matrix, mode);
                        --fPathDepth;
                        validate(path);
                    }
                    break;
                case kReverseAddPath:
                    if (fPathDepth < fPathDepthLimit) {
                        ++fPathDepth;
                        SkPath src = makePath();
                        validate(src);
                        path.reverseAddPath(src);
                        --fPathDepth;
                        validate(path);
                    }
                    break;
                case kMoveToPath: {
                    SkScalar x = makeScalar();
                    SkScalar y = makeScalar();
                    path.moveTo(x, y);
                    validate(path);
                    } break;
                case kRMoveToPath: {
                    SkScalar x = makeScalar();
                    SkScalar y = makeScalar();
                    path.rMoveTo(x, y);
                    validate(path);
                    } break;
                case kLineToPath: {
                    SkScalar x = makeScalar();
                    SkScalar y = makeScalar();
                    path.lineTo(x, y);
                    validate(path);
                    } break;
                case kRLineToPath: {
                    SkScalar x = makeScalar();
                    SkScalar y = makeScalar();
                    path.rLineTo(x, y);
                    validate(path);
                    } break;
                case kQuadToPath: {
                    SkPoint pt[2];
                    makePointArray(SK_ARRAY_COUNT(pt), pt);
                    path.quadTo(pt[0], pt[1]);
                    validate(path);
                    } break;
                case kRQuadToPath: {
                    SkPoint pt[2];
                    makePointArray(SK_ARRAY_COUNT(pt), pt);
                    path.rQuadTo(pt[0].fX, pt[0].fY, pt[1].fX, pt[1].fY);
                    validate(path);
                    } break;
                case kConicToPath: {
                    SkPoint pt[2];
                    makePointArray(SK_ARRAY_COUNT(pt), pt);
                    SkScalar weight = makeScalar();
                    path.conicTo(pt[0], pt[1], weight);
                    validate(path);
                    } break;
                case kRConicToPath: {
                    SkPoint pt[2];
                    makePointArray(SK_ARRAY_COUNT(pt), pt);
                    SkScalar weight = makeScalar();
                    path.rConicTo(pt[0].fX, pt[0].fY, pt[1].fX, pt[1].fY, weight);
                    validate(path);
                    } break;
                case kCubicToPath: {
                    SkPoint pt[3];
                    makePointArray(SK_ARRAY_COUNT(pt), pt);
                    path.cubicTo(pt[0], pt[1], pt[2]);
                    validate(path);
                    } break;
                case kRCubicToPath: {
                    SkPoint pt[3];
                    makePointArray(SK_ARRAY_COUNT(pt), pt);
                    path.rCubicTo(pt[0].fX, pt[0].fY, pt[1].fX, pt[1].fY, pt[2].fX, pt[2].fY);
                    validate(path);
                    } break;
                case kArcToPath: {
                    SkPoint pt[2];
                    makePointArray(SK_ARRAY_COUNT(pt), pt);
                    SkScalar radius = makeScalar();
                    path.arcTo(pt[0], pt[1], radius);
                    validate(path);
                    } break;
                case kArcTo2Path: {
                    SkRect oval = makeRect();
                    SkScalar startAngle = makeAngle();
                    SkScalar sweepAngle = makeAngle();
                    bool forceMoveTo = makeBool();
                    path.arcTo(oval, startAngle, sweepAngle, forceMoveTo);
                    validate(path);
                    } break;
                case kClosePath:
                    path.close();
                    validate(path);
                    break;
            }
        }
    }
    return path;
}
コード例 #11
0
ファイル: SkOpBuilder.cpp プロジェクト: OwenTan/skia
/* OPTIMIZATION: Union doesn't need to be all-or-nothing. A run of three or more convex
   paths with union ops could be locally resolved and still improve over doing the
   ops one at a time. */
bool SkOpBuilder::resolve(SkPath* result) {
    SkPath original = *result;
    int count = fOps.count();
    bool allUnion = true;
    SkPathPriv::FirstDirection firstDir = SkPathPriv::kUnknown_FirstDirection;
    for (int index = 0; index < count; ++index) {
        SkPath* test = &fPathRefs[index];
        if (kUnion_SkPathOp != fOps[index] || test->isInverseFillType()) {
            allUnion = false;
            break;
        }
        // If all paths are convex, track direction, reversing as needed.
        if (test->isConvex()) {
            SkPathPriv::FirstDirection dir;
            if (!SkPathPriv::CheapComputeFirstDirection(*test, &dir)) {
                allUnion = false;
                break;
            }
            if (firstDir == SkPathPriv::kUnknown_FirstDirection) {
                firstDir = dir;
            } else if (firstDir != dir) {
                SkPath temp;
                temp.reverseAddPath(*test);
                *test = temp;
            }
            continue;
        }
        // If the path is not convex but its bounds do not intersect the others, simplify is enough.
        const SkRect& testBounds = test->getBounds();
        for (int inner = 0; inner < index; ++inner) {
            // OPTIMIZE: check to see if the contour bounds do not intersect other contour bounds?
            if (SkRect::Intersects(fPathRefs[inner].getBounds(), testBounds)) {
                allUnion = false;
                break;
            }
        }
    }
    if (!allUnion) {
        *result = fPathRefs[0];
        for (int index = 1; index < count; ++index) {
            if (!Op(*result, fPathRefs[index], fOps[index], result)) {
                reset();
                *result = original;
                return false;
            }
        }
        reset();
        return true;
    }
    SkPath sum;
    for (int index = 0; index < count; ++index) {
        if (!Simplify(fPathRefs[index], &fPathRefs[index])) {
            reset();
            *result = original;
            return false;
        }
        if (!fPathRefs[index].isEmpty()) {
            // convert the even odd result back to winding form before accumulating it
            if (!FixWinding(&fPathRefs[index])) {
                *result = original;
                return false;
            }
            sum.addPath(fPathRefs[index]);
        }
    }
    reset();
    bool success = Simplify(sum, result);
    if (!success) {
        *result = original;
    }
    return success;
}