📄 xoutputdev.cc
字号:
updateStrokeColor(state); updateFont(state);}void XOutputDev::updateCTM(GfxState *state, double m11, double m12, double m21, double m22, double m31, double m32) { updateLineAttrs(state, gTrue);}void XOutputDev::updateLineDash(GfxState *state) { updateLineAttrs(state, gTrue);}void XOutputDev::updateFlatness(GfxState *state) { flatness = state->getFlatness();}void XOutputDev::updateLineJoin(GfxState *state) { updateLineAttrs(state, gFalse);}void XOutputDev::updateLineCap(GfxState *state) { updateLineAttrs(state, gFalse);}// unimplementedvoid XOutputDev::updateMiterLimit(GfxState *state) {}void XOutputDev::updateLineWidth(GfxState *state) { updateLineAttrs(state, gFalse);}void XOutputDev::updateLineAttrs(GfxState *state, GBool updateDash) { double width; int cap, join; double *dashPattern; int dashLength; double dashStart; char dashList[20]; int i; width = state->getTransformedLineWidth(); switch (state->getLineCap()) { case 0: cap = CapButt; break; case 1: cap = CapRound; break; case 2: cap = CapProjecting; break; default: error(-1, "Bad line cap style (%d)", state->getLineCap()); cap = CapButt; break; } switch (state->getLineJoin()) { case 0: join = JoinMiter; break; case 1: join = JoinRound; break; case 2: join = JoinBevel; break; default: error(-1, "Bad line join style (%d)", state->getLineJoin()); join = JoinMiter; break; } state->getLineDash(&dashPattern, &dashLength, &dashStart);#if 1 //~ work around a bug in XFree86 (???) if (dashLength > 0 && cap == CapProjecting) { cap = CapButt; }#endif XSetLineAttributes(display, strokeGC, xoutRound(width), dashLength > 0 ? LineOnOffDash : LineSolid, cap, join); if (updateDash && dashLength > 0) { if (dashLength > 20) dashLength = 20; for (i = 0; i < dashLength; ++i) { dashList[i] = xoutRound(state->transformWidth(dashPattern[i])); if (dashList[i] == 0) dashList[i] = 1; } XSetDashes(display, strokeGC, xoutRound(dashStart), dashList, dashLength); }}void XOutputDev::updateFillColor(GfxState *state) { GfxRGB rgb; state->getFillRGB(&rgb); if (reverseVideo) { rgb.r = 1 - rgb.r; rgb.g = 1 - rgb.g; rgb.b = 1 - rgb.b; } XSetForeground(display, fillGC, findColor(&rgb));}void XOutputDev::updateStrokeColor(GfxState *state) { GfxRGB rgb; state->getStrokeRGB(&rgb); if (reverseVideo) { rgb.r = 1 - rgb.r; rgb.g = 1 - rgb.g; rgb.b = 1 - rgb.b; } XSetForeground(display, strokeGC, findColor(&rgb));}void XOutputDev::updateFont(GfxState *state) { double m11, m12, m21, m22; text->updateFont(state); if (!(gfxFont = state->getFont())) { font = NULL; return; } if (gfxFont->getType() == fontType3) { font = NULL; return; } state->getFontTransMat(&m11, &m12, &m21, &m22); m11 *= state->getHorizScaling(); m12 *= state->getHorizScaling(); font = fontCache->getFont(xref, gfxFont, m11, m12, m21, m22); if (font) { font->updateGC(fillGC); font->updateGC(strokeGC); }}void XOutputDev::stroke(GfxState *state) { XPoint *points; int *lengths; int n, size, numPoints, i, j; // transform points n = convertPath(state, &points, &size, &numPoints, &lengths, gFalse); // draw each subpath j = 0; for (i = 0; i < n; ++i) { XDrawLines(display, pixmap, strokeGC, points + j, lengths[i], CoordModeOrigin); j += lengths[i]; } // free points and lengths arrays if (points != tmpPoints) gfree(points); if (lengths != tmpLengths) gfree(lengths);}void XOutputDev::fill(GfxState *state) { doFill(state, WindingRule);}void XOutputDev::eoFill(GfxState *state) { doFill(state, EvenOddRule);}//// X doesn't color the pixels on the right-most and bottom-most// borders of a polygon. This means that one-pixel-thick polygons// are not colored at all. I think this is supposed to be a// feature, but I can't figure out why. So after it fills a// polygon, it also draws lines around the border. This is done// only for single-component polygons, since it's not very// compatible with the compound polygon kludge (see convertPath()).//void XOutputDev::doFill(GfxState *state, int rule) { XPoint *points; int *lengths; int n, size, numPoints, i, j; // set fill rule XSetFillRule(display, fillGC, rule); // transform points, build separate polygons n = convertPath(state, &points, &size, &numPoints, &lengths, gTrue); // fill them j = 0; for (i = 0; i < n; ++i) { XFillPolygon(display, pixmap, fillGC, points + j, lengths[i], Complex, CoordModeOrigin); if (state->getPath()->getNumSubpaths() == 1) { XDrawLines(display, pixmap, fillGC, points + j, lengths[i], CoordModeOrigin); } j += lengths[i] + 1; } // free points and lengths arrays if (points != tmpPoints) gfree(points); if (lengths != tmpLengths) gfree(lengths);}void XOutputDev::clip(GfxState *state) { doClip(state, WindingRule);}void XOutputDev::eoClip(GfxState *state) { doClip(state, EvenOddRule);}void XOutputDev::doClip(GfxState *state, int rule) { Region region, region2; XPoint *points; int *lengths; int n, size, numPoints, i, j; // transform points, build separate polygons n = convertPath(state, &points, &size, &numPoints, &lengths, gTrue); // construct union of subpath regions // (XPolygonRegion chokes if there aren't at least three points -- // this happens if the PDF file does moveto/closepath/clip, which // sets an empty clipping region) if (lengths[0] > 2) { region = XPolygonRegion(points, lengths[0], rule); } else { region = XCreateRegion(); } j = lengths[0] + 1; for (i = 1; i < n; ++i) { if (lengths[i] > 2) { region2 = XPolygonRegion(points + j, lengths[i], rule); } else { region2 = XCreateRegion(); } XUnionRegion(region2, region, region); XDestroyRegion(region2); j += lengths[i] + 1; } // intersect region with clipping region XIntersectRegion(region, clipRegion, clipRegion); XDestroyRegion(region); XSetRegion(display, strokeGC, clipRegion); XSetRegion(display, fillGC, clipRegion); // free points and lengths arrays if (points != tmpPoints) gfree(points); if (lengths != tmpLengths) gfree(lengths);}//// Transform points in the path and convert curves to line segments.// Builds a set of subpaths and returns the number of subpaths.// If <fillHack> is set, close any unclosed subpaths and activate a// kludge for polygon fills: First, it divides up the subpaths into// non-overlapping polygons by simply comparing bounding rectangles.// Then it connects subaths within a single compound polygon to a single// point so that X can fill the polygon (sort of).//int XOutputDev::convertPath(GfxState *state, XPoint **points, int *size, int *numPoints, int **lengths, GBool fillHack) { GfxPath *path; BoundingRect *rects; BoundingRect rect; int n, i, ii, j, k, k0; // get path and number of subpaths path = state->getPath(); n = path->getNumSubpaths(); // allocate lengths array if (n < numTmpSubpaths) *lengths = tmpLengths; else *lengths = (int *)gmalloc(n * sizeof(int)); // allocate bounding rectangles array if (fillHack) { if (n < numTmpSubpaths) rects = tmpRects; else rects = (BoundingRect *)gmalloc(n * sizeof(BoundingRect)); } else { rects = NULL; } // do each subpath *points = tmpPoints; *size = numTmpPoints; *numPoints = 0; for (i = 0; i < n; ++i) { // transform the points j = *numPoints; convertSubpath(state, path->getSubpath(i), points, size, numPoints); // construct bounding rectangle if (fillHack) { rects[i].xMin = rects[i].xMax = (*points)[j].x; rects[i].yMin = rects[i].yMax = (*points)[j].y; for (k = j + 1; k < *numPoints; ++k) { if ((*points)[k].x < rects[i].xMin) rects[i].xMin = (*points)[k].x; else if ((*points)[k].x > rects[i].xMax) rects[i].xMax = (*points)[k].x; if ((*points)[k].y < rects[i].yMin) rects[i].yMin = (*points)[k].y; else if ((*points)[k].y > rects[i].yMax) rects[i].yMax = (*points)[k].y; } } // close subpath if necessary if (fillHack && ((*points)[*numPoints-1].x != (*points)[j].x || (*points)[*numPoints-1].y != (*points)[j].y)) { addPoint(points, size, numPoints, (*points)[j].x, (*points)[j].y); } // length of this subpath (*lengths)[i] = *numPoints - j; // leave an extra point for compound fill hack if (fillHack) addPoint(points, size, numPoints, 0, 0); } // kludge: munge any points that are *way* out of bounds - these can // crash certain (buggy) X servers for (i = 0; i < *numPoints; ++i) { if ((*points)[i].x < -pixmapW) { (*points)[i].x = -pixmapW; } else if ((*points)[i].x > 2 * pixmapW) { (*points)[i].x = 2 * pixmapW; } if ((*points)[i].y < -pixmapH) { (*points)[i].y = -pixmapH; } else if ((*points)[i].y > 2 * pixmapH) { (*points)[i].y = 2 * pixmapH; } } // combine compound polygons if (fillHack) { i = j = k = 0; while (i < n) { // start with subpath i rect = rects[i]; (*lengths)[j] = (*lengths)[i]; k0 = k; (*points)[k + (*lengths)[i]] = (*points)[k0]; k += (*lengths)[i] + 1; ++i; // combine overlapping polygons do { // look for the first subsequent subpath, if any, which overlaps for (ii = i; ii < n; ++ii) { if (rects[ii].xMax > rects[i].xMin && rects[ii].xMin < rects[i].xMax && rects[ii].yMax > rects[i].yMin && rects[ii].yMin < rects[i].yMax) { break; } } // if there is an overlap, combine the polygons if (ii < n) { for (; i <= ii; ++i) { if (rects[i].xMin < rect.xMin) rect.xMin = rects[j].xMin; if (rects[i].xMax > rect.xMax) rect.xMax = rects[j].xMax; if (rects[i].yMin < rect.yMin) rect.yMin = rects[j].yMin; if (rects[i].yMax > rect.yMax) rect.yMax = rects[j].yMax; (*lengths)[j] += (*lengths)[i] + 1; (*points)[k + (*lengths)[i]] = (*points)[k0]; k += (*lengths)[i] + 1; } } } while (ii < n && i < n); ++j; } // free bounding rectangles if (rects != tmpRects) gfree(rects); n = j; } return n;}//// Transform points in a single subpath and convert curves to line// segments.//void XOutputDev::convertSubpath(GfxState *state, GfxSubpath *subpath, XPoint **points, int *size, int *n) { double x0, y0, x1, y1, x2, y2, x3, y3; int m, i; m = subpath->getNumPoints(); i = 0; while (i < m) { if (i >= 1 && subpath->getCurve(i)) { state->transform(subpath->getX(i-1), subpath->getY(i-1), &x0, &y0); state->transform(subpath->getX(i), subpath->getY(i), &x1, &y1); state->transform(subpath->getX(i+1), subpath->getY(i+1), &x2, &y2); state->transform(subpath->getX(i+2), subpath->getY(i+2), &x3, &y3); doCurve(points, size, n, x0, y0, x1, y1, x2, y2, x3, y3); i += 3; } else { state->transform(subpath->getX(i), subpath->getY(i), &x1, &y1); addPoint(points, size, n, xoutRound(x1), xoutRound(y1)); ++i; } }}//// Subdivide a Bezier curve. This uses floating point to avoid// propagating rounding errors. (The curves look noticeably more// jagged with integer arithmetic.)//void XOutputDev::doCurve(XPoint **points, int *size, int *n, double x0, double y0, double x1, double y1, double x2, double y2, double x3, double y3) { double x[(1<<maxCurveSplits)+1][3]; double y[(1<<maxCurveSplits)+1][3]; int next[1<<maxCurveSplits]; int p1, p2, p3; double xx1, yy1, xx2, yy2; double dx, dy, mx, my, d1, d2; double xl0, yl0, xl1, yl1, xl2, yl2; double xr0, yr0, xr1, yr1, xr2, yr2, xr3, yr3; double xh, yh; double flat; flat = (double)(flatness * flatness); if (flat < 1) flat = 1; // initial segment p1 = 0; p2 = 1<<maxCurveSplits; x[p1][0] = x0; y[p1][0] = y0; x[p1][1] = x1; y[p1][1] = y1; x[p1][2] = x2; y[p1][2] = y2; x[p2][0] = x3; y[p2][0] = y3; next[p1] = p2; while (p1 < (1<<maxCurveSplits)) { // get next segment xl0 = x[p1][0]; yl0 = y[p1][0]; xx1 = x[p1][1]; yy1 = y[p1][1]; xx2 = x[p1][2]; yy2 = y[p1][2]; p2 = next[p1]; xr3 = x[p2][0]; yr3 = y[p2][0]; // compute distances from control points to midpoint of the // straight line (this is a bit of a hack, but it's much faster // than computing the actual distances to the line) mx = (xl0 + xr3) * 0.5; my = (yl0 + yr3) * 0.5; dx = xx1 - mx; dy = yy1 - my; d1 = dx*dx + dy*dy; dx = xx2 - mx; dy = yy2 - my; d2 = dx*dx + dy*dy; // if curve is flat enough, or no more divisions allowed then // add the straight line segment if (p2 - p1 <= 1 || (d1 <= flat && d2 <= flat)) { addPoint(points, size, n, xoutRound(xr3), xoutRound(yr3)); p1 = p2; // otherwise, subdivide the curve } else { xl1 = (xl0 + xx1) * 0.5; yl1 =
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -