📄 splash.cc
字号:
} // segment with |dy| > |dx| } else { dxdy = seg->dxdy; if (y0 > y1) { t = x0; x0 = x1; x1 = t; t = y0; y0 = y1; y1 = t; } if ((clipRes = state->clip->testRect(x0 <= x1 ? x0 : x1, y0, x0 <= x1 ? x1 : x0, y1)) != splashClipAllOutside) { drawPixel(x0, y0, state->strokePattern, state->strokeAlpha, clipRes == splashClipAllInside); for (y = y0 + 1; y <= y1 - 1; ++y) { x = splashFloor(seg->x0 + ((SplashCoord)y - seg->y0) * dxdy); drawPixel(x, y, state->strokePattern, state->strokeAlpha, clipRes == splashClipAllInside); } drawPixel(x1, y1, state->strokePattern, state->strokeAlpha, clipRes == splashClipAllInside); } } ++nClipRes[clipRes]; } if (nClipRes[splashClipPartial] || (nClipRes[splashClipAllInside] && nClipRes[splashClipAllOutside])) { opClipRes = splashClipPartial; } else if (nClipRes[splashClipAllInside]) { opClipRes = splashClipAllInside; } else { opClipRes = splashClipAllOutside; }}void Splash::strokeWide(SplashXPath *xPath) { SplashXPathSeg *seg, *seg2; SplashPath *widePath; SplashCoord d, dx, dy, wdx, wdy, dxPrev, dyPrev, wdxPrev, wdyPrev; SplashCoord dotprod, miter; int i, j; dx = dy = wdx = wdy = 0; // make gcc happy dxPrev = dyPrev = wdxPrev = wdyPrev = 0; // make gcc happy for (i = 0, seg = xPath->segs; i < xPath->length; ++i, ++seg) { // save the deltas for the previous segment; if this is the first // segment on a subpath, compute the deltas for the last segment // on the subpath (which may be used to draw a line join) if (seg->flags & splashXPathFirst) { for (j = i + 1, seg2 = &xPath->segs[j]; j < xPath->length; ++j, ++seg2) { if (seg2->flags & splashXPathLast) { d = splashDist(seg2->x0, seg2->y0, seg2->x1, seg2->y1); if (d == 0) { //~ not clear what the behavior should be for joins with d==0 dxPrev = 0; dyPrev = 1; } else { d = (SplashCoord)1 / d; dxPrev = d * (seg2->x1 - seg2->x0); dyPrev = d * (seg2->y1 - seg2->y0); } wdxPrev = (SplashCoord)0.5 * state->lineWidth * dxPrev; wdyPrev = (SplashCoord)0.5 * state->lineWidth * dyPrev; break; } } } else { dxPrev = dx; dyPrev = dy; wdxPrev = wdx; wdyPrev = wdy; } // compute deltas for this line segment d = splashDist(seg->x0, seg->y0, seg->x1, seg->y1); if (d == 0) { // we need to draw end caps on zero-length lines //~ not clear what the behavior should be for splashLineCapButt with d==0 dx = 0; dy = 1; } else { d = (SplashCoord)1 / d; dx = d * (seg->x1 - seg->x0); dy = d * (seg->y1 - seg->y0); } wdx = (SplashCoord)0.5 * state->lineWidth * dx; wdy = (SplashCoord)0.5 * state->lineWidth * dy; // initialize the path (which will be filled) widePath = new SplashPath(); widePath->moveTo(seg->x0 - wdy, seg->y0 + wdx); // draw the start cap if (seg->flags & splashXPathEnd0) { switch (state->lineCap) { case splashLineCapButt: widePath->lineTo(seg->x0 + wdy, seg->y0 - wdx); break; case splashLineCapRound: widePath->arcCWTo(seg->x0 + wdy, seg->y0 - wdx, seg->x0, seg->y0); break; case splashLineCapProjecting: widePath->lineTo(seg->x0 - wdx - wdy, seg->y0 + wdx - wdy); widePath->lineTo(seg->x0 - wdx + wdy, seg->y0 - wdx - wdy); widePath->lineTo(seg->x0 + wdy, seg->y0 - wdx); break; } } else { widePath->lineTo(seg->x0 + wdy, seg->y0 - wdx); } // draw the left side of the segment widePath->lineTo(seg->x1 + wdy, seg->y1 - wdx); // draw the end cap if (seg->flags & splashXPathEnd1) { switch (state->lineCap) { case splashLineCapButt: widePath->lineTo(seg->x1 - wdy, seg->y1 + wdx); break; case splashLineCapRound: widePath->arcCWTo(seg->x1 - wdy, seg->y1 + wdx, seg->x1, seg->y1); break; case splashLineCapProjecting: widePath->lineTo(seg->x1 + wdx + wdy, seg->y1 - wdx + wdy); widePath->lineTo(seg->x1 + wdx - wdy, seg->y1 + wdx + wdy); widePath->lineTo(seg->x1 - wdy, seg->y1 + wdx); break; } } else { widePath->lineTo(seg->x1 - wdy, seg->y1 + wdx); } // draw the right side of the segment widePath->lineTo(seg->x0 - wdy, seg->y0 + wdx); // fill the segment fillWithPattern(widePath, gTrue, state->strokePattern, state->strokeAlpha); delete widePath; // draw the line join if (!(seg->flags & splashXPathEnd0)) { widePath = NULL; switch (state->lineJoin) { case splashLineJoinMiter: dotprod = -(dx * dxPrev + dy * dyPrev); if (splashAbs(splashAbs(dotprod) - 1) > 0.01) { widePath = new SplashPath(); widePath->moveTo(seg->x0, seg->y0); miter = (SplashCoord)2 / ((SplashCoord)1 - dotprod); if (splashSqrt(miter) <= state->miterLimit) { miter = splashSqrt(miter - 1); if (dy * dxPrev > dx * dyPrev) { widePath->lineTo(seg->x0 + wdyPrev, seg->y0 - wdxPrev); widePath->lineTo(seg->x0 + wdy - miter * wdx, seg->y0 - wdx - miter * wdy); widePath->lineTo(seg->x0 + wdy, seg->y0 - wdx); } else { widePath->lineTo(seg->x0 - wdyPrev, seg->y0 + wdxPrev); widePath->lineTo(seg->x0 - wdy - miter * wdx, seg->y0 + wdx - miter * wdy); widePath->lineTo(seg->x0 - wdy, seg->y0 + wdx); } } else { if (dy * dxPrev > dx * dyPrev) { widePath->lineTo(seg->x0 + wdyPrev, seg->y0 - wdxPrev); widePath->lineTo(seg->x0 + wdy, seg->y0 - wdx); } else { widePath->lineTo(seg->x0 - wdyPrev, seg->y0 + wdxPrev); widePath->lineTo(seg->x0 - wdy, seg->y0 + wdx); } } } break; case splashLineJoinRound: widePath = new SplashPath(); widePath->moveTo(seg->x0 + wdy, seg->y0 - wdx); widePath->arcCWTo(seg->x0 + wdy, seg->y0 - wdx, seg->x0, seg->y0); break; case splashLineJoinBevel: widePath = new SplashPath(); widePath->moveTo(seg->x0, seg->y0); if (dy * dxPrev > dx * dyPrev) { widePath->lineTo(seg->x0 + wdyPrev, seg->y0 - wdxPrev); widePath->lineTo(seg->x0 + wdy, seg->y0 - wdx); } else { widePath->lineTo(seg->x0 - wdyPrev, seg->y0 + wdxPrev); widePath->lineTo(seg->x0 - wdy, seg->y0 + wdx); } break; } if (widePath) { fillWithPattern(widePath, gTrue, state->strokePattern, state->strokeAlpha); delete widePath; } } }}SplashXPath *Splash::makeDashedPath(SplashXPath *xPath) { SplashXPath *dPath; GBool lineDashStartOn, lineDashOn; GBool atSegStart, atSegEnd, atDashStart, atDashEnd; int lineDashStartIdx, lineDashIdx, subpathStart; SplashCoord lineDashTotal, lineDashStartPhase, lineDashDist; int segIdx; SplashXPathSeg *seg; SplashCoord sx0, sy0, sx1, sy1, ax0, ay0, ax1, ay1, dist; int i; dPath = new SplashXPath(); lineDashTotal = 0; for (i = 0; i < state->lineDashLength; ++i) { lineDashTotal += state->lineDash[i]; } lineDashStartPhase = state->lineDashPhase; i = splashFloor(lineDashStartPhase / lineDashTotal); lineDashStartPhase -= (SplashCoord)i * lineDashTotal; lineDashStartOn = gTrue; lineDashStartIdx = 0; while (lineDashStartPhase >= state->lineDash[lineDashStartIdx]) { lineDashStartOn = !lineDashStartOn; lineDashStartPhase -= state->lineDash[lineDashStartIdx]; ++lineDashStartIdx; } segIdx = 0; seg = xPath->segs; sx0 = seg->x0; sy0 = seg->y0; sx1 = seg->x1; sy1 = seg->y1; dist = splashDist(sx0, sy0, sx1, sy1); lineDashOn = lineDashStartOn; lineDashIdx = lineDashStartIdx; lineDashDist = state->lineDash[lineDashIdx] - lineDashStartPhase; atSegStart = gTrue; atDashStart = gTrue; subpathStart = dPath->length; while (segIdx < xPath->length) { ax0 = sx0; ay0 = sy0; if (dist <= lineDashDist) { ax1 = sx1; ay1 = sy1; lineDashDist -= dist; dist = 0; atSegEnd = gTrue; atDashEnd = lineDashDist == 0 || (seg->flags & splashXPathLast); } else { ax1 = sx0 + (lineDashDist / dist) * (sx1 - sx0); ay1 = sy0 + (lineDashDist / dist) * (sy1 - sy0); sx0 = ax1; sy0 = ay1; dist -= lineDashDist; lineDashDist = 0; atSegEnd = gFalse; atDashEnd = gTrue; } if (lineDashOn) { dPath->addSegment(ax0, ay0, ax1, ay1, atDashStart, atDashEnd, atDashStart, atDashEnd); // end of closed subpath if (atSegEnd && (seg->flags & splashXPathLast) && !(seg->flags & splashXPathEnd1)) { dPath->segs[subpathStart].flags &= ~splashXPathEnd0; dPath->segs[dPath->length - 1].flags &= ~splashXPathEnd1; } } if (atDashEnd) { lineDashOn = !lineDashOn; if (++lineDashIdx == state->lineDashLength) { lineDashIdx = 0; } lineDashDist = state->lineDash[lineDashIdx]; atDashStart = gTrue; } else { atDashStart = gFalse; } if (atSegEnd) { if (++segIdx < xPath->length) { ++seg; sx0 = seg->x0; sy0 = seg->y0; sx1 = seg->x1; sy1 = seg->y1; dist = splashDist(sx0, sy0, sx1, sy1); if (seg->flags & splashXPathFirst) { lineDashOn = lineDashStartOn; lineDashIdx = lineDashStartIdx; lineDashDist = state->lineDash[lineDashIdx] - lineDashStartPhase; atDashStart = gTrue; subpathStart = dPath->length; } } atSegStart = gTrue; } else { atSegStart = gFalse; } } return dPath;}SplashError Splash::fill(SplashPath *path, GBool eo) { if (debugMode) { printf("fill [eo:%d]:\n", eo); dumpPath(path); } return fillWithPattern(path, eo, state->fillPattern, state->fillAlpha);}SplashError Splash::fillWithPattern(SplashPath *path, GBool eo, SplashPattern *pattern, SplashCoord alpha) { SplashXPath *xPath; SplashXPathScanner *scanner; int xMinI, yMinI, xMaxI, yMaxI, x0, x1, y; SplashClipResult clipRes, clipRes2; if (path->length == 0) { return splashErrEmptyPath; } xPath = new SplashXPath(path, state->flatness, gTrue); xPath->sort(); scanner = new SplashXPathScanner(xPath, eo); // get the min and max x and y values scanner->getBBox(&xMinI, &yMinI, &xMaxI, &yMaxI); // check clipping if ((clipRes = state->clip->testRect(xMinI, yMinI, xMaxI, yMaxI)) != splashClipAllOutside) { // limit the y range if (yMinI < state->clip->getYMin()) { yMinI = state->clip->getYMin(); } if (yMaxI > state->clip->getYMax()) { yMaxI = state->clip->getYMax(); } // draw the spans for (y = yMinI; y <= yMaxI; ++y) { while (scanner->getNextSpan(y, &x0, &x1)) { if (clipRes == splashClipAllInside) { drawSpan(x0, x1, y, pattern, alpha, gTrue); } else { // limit the x range if (x0 < state->clip->getXMin()) { x0 = state->clip->getXMin(); } if (x1 > state->clip->getXMax()) { x1 = state->clip->getXMax(); } clipRes2 = state->clip->testSpan(x0, x1, y); drawSpan(x0, x1, y, pattern, alpha, clipRes2 == splashClipAllInside); } } } } opClipRes = clipRes; delete scanner; delete xPath; return splashOk;}SplashError Splash::xorFill(SplashPath *path, GBool eo) { SplashXPath *xPath; SplashXPathScanner *scanner; int xMinI, yMinI, xMaxI, yMaxI, x0, x1, y; SplashClipResult clipRes, clipRes2; if (path->length == 0) { return splashErrEmptyPath; } xPath = new SplashXPath(path, state->flatness, gTrue); xPath->sort(); scanner = new SplashXPathScanner(xPath, eo); // get the min and max x and y values scanner->getBBox(&xMinI, &yMinI, &xMaxI, &yMaxI); // check clipping if ((clipRes = state->clip->testRect(xMinI, yMinI, xMaxI, yMaxI)) != splashClipAllOutside) { // limit the y range if (yMinI < state->clip->getYMin()) { yMinI = state->clip->getYMin(); } if (yMaxI > state->clip->getYMax()) { yMaxI = state->clip->getYMax(); } // draw the spans for (y = yMinI; y <= yMaxI; ++y) { while (scanner->getNextSpan(y, &x0, &x1)) { if (clipRes == splashClipAllInside) { xorSpan(x0, x1, y, state->fillPattern, gTrue); } else { // limit the x range if (x0 < state->clip->getXMin()) { x0 = state->clip->getXMin(); } if (x1 > state->clip->getXMax()) { x1 = state->clip->getXMax(); } clipRes2 = state->clip->testSpan(x0, x1, y); xorSpan(x0, x1, y, state->fillPattern, clipRes2 == splashClipAllInside); } } } } opClipRes = clipRes; delete scanner; delete xPath; return splashOk;}void Splash::drawPixel(int x, int y, SplashColorPtr color, SplashCoord alpha, GBool noClip) { SplashBlendFunc blendFunc; SplashColorPtr p; SplashColor dest, blend; int alpha2, ialpha2; Guchar t; if (noClip || state->clip->test(x, y)) { if (alpha != 1 || softMask || state->blendFunc) { blendFunc = state->blendFunc ? state->blendFunc : &blendNormal; if (softMask) { alpha2 = (int)(alpha * softMask->data[y * softMask->rowSize + x]); } else { alpha2 = (int)(alpha * 255); } ialpha2 = 255 - alpha2; switch (bitmap->mode) { case splashModeMono1: p = &bitmap->data[y * bitmap->rowSize + (x >> 3)]; dest[0] = (*p >> (7 - (x & 7))) & 1; (*blendFunc)(color, dest, blend, bitmap->mode); t = (alpha2 * blend[0] + ialpha2 * dest[0]) >> 8; if (t) { *p |= 0x80 >> (x & 7); } else { *p &= ~(0x80 >> (x & 7)); } break; case splashModeMono8: p = &bitmap->data[y * bitmap->rowSize + x]; (*blendFunc)(color, p, blend, bitmap->mode); // note: floor(x / 255) = x >> 8 (for 16-bit x) p[0] = (alpha2 * blend[0] + ialpha2 * p[0]) >> 8; break; case splashModeAMono8: p = &bitmap->data[y * bitmap->rowSize + 2 * x]; (*blendFunc)(color, p, blend, bitmap->mode); p[0] = (alpha2 * blend[0] + ialpha2 * p[0]) >> 8; p[1] = (alpha2 * blend[1] + ialpha2 * p[1]) >> 8; break; case splashModeRGB8: case splashModeBGR8: p = &bitmap->data[y * bitmap->rowSize + 3 * x]; (*blendFunc)(color, p, blend, bitmap->mode); p[0] = (alpha2 * blend[0] + ialpha2 * p[0]) >> 8; p[1] = (alpha2 * blend[1] + ialpha2 * p[1]) >> 8; p[2] = (alpha2 * blend[2] + ialpha2 * p[2]) >> 8; break; case splashModeARGB8: case splashModeBGRA8:#if SPLASH_CMYK case splashModeCMYK8:#endif p = &bitmap->data[y * bitmap->rowSize + 4 * x]; (*blendFunc)(color, p, blend, bitmap->mode); p[0] = (alpha2 * blend[0] + ialpha2 * p[0]) >> 8; p[1] = (alpha2 * blend[1] + ialpha2 * p[1]) >> 8; p[2] = (alpha2 * blend[2] + ialpha2 * p[2]) >> 8;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -