void MacPrinterCanvas::setmapmode(HDC hdc) { int s = int(1440./scale_); MWassert(SetMapMode(hdc, MM_ANISOTROPIC)); //MWassert(SetWindowExtEx(hdc, 1440, 1440, NULL)); MWassert(SetWindowExtEx(hdc, s, s, NULL)); MWassert(SetViewportExtEx(hdc, GetDeviceCaps(hdc, LOGPIXELSX), -GetDeviceCaps(hdc, LOGPIXELSY), NULL)); }
// ----------------------------------------------------------------------- // Render an image onto the GDI surface. The image is transformed in // terms of scaling only initially (all that Windows 3.1 supports). // Rotation is initially not supported. // ----------------------------------------------------------------------- void MWcanvas16::image(const Raster* ras, Coord x, Coord y) { // // convert the coordinates to TWIPS for the page space to device space // mapping. // Coord tx, ty, tw, th; if (transformed_) { matrix().transform(x, y, tx, ty); matrix().transform(x+ras->width(), y+ras->height(), tw, th); tw -= tx; th -= ty; } else { tx = x; ty = y; tw = ras->width(); ty = ras->height(); } int x0 = COORD2TWIPS( tx ); int y0 = COORD2TWIPS( ty ); int width = COORD2TWIPS( tw ); int height = COORD2TWIPS( th ); // ---- blt... the destination will be transformed ---- MWassert( StretchBlt(drawable_, x0, y0 + height, width, - height, ras->rep()->deviceContext(), 0, 0, ras->pwidth(), ras->pheight(), SRCCOPY) ); }
void MWcanvas16::flush() { // ---- check if there is anything to do ---- int nchars = (int) (text_ptr_ - text_buff_); if ((nchars == 0) || (lg_font_ == nil)) return; // ---- render the text ---- SetBkMode(drawable_, TRANSPARENT); FontRep* fr = lg_font_->rep(nil); MWassert(fr); // the one consequence of caching the font is that it is no longer possible // to transform the angle like this at this point. so we lose rotated text // but gain the ability to use different fonts! // fr->orientation(transformAngle()); // HFONT new_fnt = fr->Create(); // if (!new_fnt) { // new_fnt = fr->Create(); // } HFONT old_fnt = (HFONT) SelectObject(drawable_, fr->HFont()); SetTextAlign(drawable_, TA_LEFT | TA_BASELINE | TA_NOUPDATECP); TextOut(drawable_, text_x0_, text_y0_, text_buff_, nchars); SelectObject(drawable_, old_fnt); // DeleteObject( SelectObject(drawable_, old_fnt)); // ---- reset the buffer ---- text_ptr_ = text_buff_; }
// ----------------------------------------------------------------------- // Changes the Color to use when rendering onto the canvas. // ----------------------------------------------------------------------- void MWcanvas16::color(const Color* c) { // ---- render anything that was buffered ---- flush(); // ---- reference new color ---- Resource::ref(c); Resource::unref(lg_color_); lg_color_ = c; // ---- set new pen color ---- pen_stats_.lopnColor = c->rep()->msColor(); pen_ = CreatePenIndirect(&pen_stats_); DeleteObject( SelectObject(drawable_, pen_)); // ---- set new brush color ---- if (c->rep()->stipple) { // THIS NEEDS WORK // // brush_stats_.lbStyle = BS_PATTERN; // brush_stats_.lbHatch = (long) c->rep()->stipple->hbm_; } else { brush_stats_.lbStyle = BS_SOLID; brush_stats_.lbColor = c->rep()->msColor(); } brush_ = CreateBrushIndirect(&brush_stats_); DeleteObject( SelectObject(drawable_, brush_)); // ---- set text color ---- SetTextColor(drawable_, c->rep()->msColor()); // ---- set color operation ---- ColorRep* r = c->rep(); if (r->op == Color::Copy) { SetROP2(drawable_, R2_COPYPEN); } else if (r->op == Color::Xor) { // SetROP2(drawable_, R2_XORPEN); SetROP2(drawable_, 6); // this is insane, but... } else if (r->op == Color::Invisible) { SetROP2(drawable_, R2_NOP); } else { // ----- unrecognized color mode ---- MWassert(0); } }
void MWcanvas16::fill(const Color* c) { if (c->rep()->stipple) { // ---- stipple some color into the area ---- stencilFill(c->rep()->stipple, c); } else { PathRenderInfo* p = &MWcanvas16::path_; int n = (int) (p->cur_point_ - p->point_); if (n <= 2) { return; } flush(); color(c); HPEN hpen = (HPEN)SelectObject(drawable_, CreatePen(PS_SOLID, 0, lg_color_->rep()->msColor())); POINT* pt = p->point_; if (xrect(pt, n)) { // ---- draw a rectangle ---- int x = Math::min(pt[0].x, pt[2].x); int y = Math::min(pt[0].y, pt[2].y); int x1 = Math::max(pt[0].x, pt[2].x); int y1 = Math::max(pt[0].y, pt[2].y); Rectangle(drawable_, x, y, x1, y1); } else { Polygon(drawable_, pt, n); } DeleteObject(SelectObject(drawable_, hpen)); } #ifdef DEBUG // ---- canvas debug ---- MWassert( LPtoDP(drawable_, pt, n) ); printf("fill "); for (int i = 0; i < n; i++) { BOOL vis = PtVisible(drawable_, pt[i].x, pt[i].y); if (vis) printf("[%d,%d] ", pt[i].x, pt[i].y); else printf("(%d,%d> ", pt[i].x, pt[i].y); } printf("\n"); #endif }
// ----------------------------------------------------------------------- // Stencil the "set" bits of the bitmap onto the canvas in the given color // at the given origin. The origin is in terms of the point system with // the origin in the lower left, which must be converted to the device // coordinate system which has an origin in the upper left. Further, the // blt coordinates must be adjusted this way as well. // // If the transformation matrix is identity, the bitmap is simply blt'd // using the raster operation discussed in the Petzold V3.0 book on page // 624 which transfers only the black bits. It corresponds to the operation // ((Destination ^ Pattern) & Source) ^ Pattern. If the transformer is not // identity, then the Windows function StretchBlt is used to scale the // bitmap. The default mode of STRETCH_ANDSCANS is appropriate since it // favors the black bits. // // Currently, a rotated bitmap is NOT supported! // ----------------------------------------------------------------------- void MWcanvas16::stencil( const Bitmap* mask, // bitmap to render const Color* c, // color to use Coord x, // x-coordinate Coord y) // y-coordinate { BitmapRep& br = * mask->rep(); HBITMAP hbm = CreateBitmapIndirect((BITMAP*) &(br.bm_)); HDC mem_hdc = CreateCompatibleDC(drawable_); SelectObject(mem_hdc, hbm); // // convert the coordinates to TWIPS for the page space to device space // mapping. // int x0 = COORD2TWIPS( x + mask->left_bearing() ); int y0 = COORD2TWIPS( y - mask->descent() ); int width = COORD2TWIPS( mask->width() ); int height = COORD2TWIPS( mask->height() ); // ---- set the color to use ---- flush(); color(c); // For some reason, text color must be black when stenciling or the // colors of the stencil are affected. SetTextColor(drawable_, RGB(0, 0, 0)); // ---- blt... the destination will be transformed ---- MWassert( StretchBlt(drawable_, x0, y0 + height, width, - height, mem_hdc, 0, 0, br.bm_.bmWidth, br.bm_.bmHeight, 0xB8074AL) ); // ---- cleanup ---- DeleteDC(mem_hdc); DeleteObject(hbm); }
void MWcanvas16::clip() { flush(); // ---- make sure there are multiple points ---- PathRenderInfo* p = &path_; POINT* pt = p->point_; int n = (int) (p->cur_point_ - p->point_); if (n <= 2) { return; } // // The path must be in terms of device units for specification of // clipping... so we transform the path specifications from logical // units (TWIPS) to device units before setting the clipping. // if(drawable_ == nil) // sometimes its null because of event input -- just ignore return; MWassert( LPtoDP(drawable_, pt, n) ); // ---- create a region to represent clipping ---- HRGN clip; if (xrect(pt, n)) { // ---- rectangular clipping area ---- RECT xr; xr.left = Math::min(pt[0].x, pt[2].x); xr.top = Math::min(pt[0].y, pt[2].y); xr.right = Math::max(pt[0].x, pt[2].x); xr.bottom = Math::max(pt[0].y, pt[2].y); clip = CreateRectRgn(xr.left, xr.top, xr.right, xr.bottom ); } else { clip = CreatePolygonRgn(pt, n, WINDING); } #if 1 // ---- merge with existing clipping area ---- HRGN intersect = CreateRectRgn(0,0,0,0); CombineRgn(intersect, clipping_, clip, RGN_AND); DeleteObject(clip); clip = intersect; #endif //DebugMessage // ---- set new clipping area ---- SelectClipRgn(drawable_, clip); DeleteObject(clipping_); clipping_ = clip; #ifdef DEBUG // ---- canvas debug ---- printf("clip "); for (int i = 0; i < n; i++) { printf("[%d,%d] ", pt[i].x, pt[i].y); } printf("\n"); #endif }