SubtreeRenderState NodeEffect::RenderSubtree(RenderRegion* pRender, Node** ppNextNode, BOOL bClip) { if (pRender == NULL) // If no render region supplied, assume we need to be rendered return SUBTREE_ROOTANDCHILDREN; // Go find out about my bounding rectangle DocRect BoundingRect = GetBoundingRect(); DocRect ClipRect = pRender->GetClipRect(); if (bClip && !ClipRect.IsIntersectedWith(BoundingRect)) // If not within the clipping rect then return SUBTREE_NORENDER; // Don't render us or our children // Ask Helper function to set up cacheing for me... // AMB wonders whethere this was commented out during porting - 20051212 // if (RenderCached(pRender)) // If we can find a cached bitmap for this node and render it // { // return SUBTREE_NORENDER; // Then tell the renderer to move on without doing any more... // } return SUBTREE_ROOTANDCHILDREN; // Else we must render ourselves and our children }
void BitmapExportPaletteControl::RenderPalette(DocRect *pPaletteSize, RenderRegion *pRender, INT32 controlHeight, DocRect* pClipRect) { INT32 nColours = m_Palette.GetNumberOfColours(); // See if the background needs rendering if (nColours < m_NumberOfColoursAtLastRedraw) RenderGrey(pPaletteSize, pRender); m_NumberOfColoursAtLastRedraw = nColours; pRender->SetLineColour(COLOUR_BLACK); DocRect cell; // Draw each cell in turn for (INT32 i = 0; i < nColours; ++i) { GetRectForCell(i, &cell, controlHeight); if (cell.IsIntersectedWith(*pClipRect)) { BYTE r, g, b; r = m_Palette.GetRed(i); g = m_Palette.GetGreen(i); b = m_Palette.GetBlue(i); DrawCell(&cell, DocColour(r, g, b), m_Palette.GetFlags(i), pRender, IsColourWebSafe(r, g, b), i == m_SelectedCell); } } // Draw the mouse over high light if (m_MouseOverCell != INVALID_COLOUR_VALUE) { GetRectForCell(m_MouseOverCell, &cell, controlHeight); pRender->SetFillColour(COLOUR_TRANS); pRender->SetLineColour(COLOUR_WHITE); pRender->DrawRect(&cell); } }
BOOL OpNudge::IsNudgeOK(BOOL dx,BOOL dy) { // Get the selection SelRange* pSel = GetApplication()->FindSelection(); ERROR2IF(pSel == NULL,FALSE,"Awooga, NULL sel range"); // Find out the bounding rectangle of the selection DocRect BoundingRect = pSel->GetBoundingRect(); // Find out the Pasteboard rect DocRect PasteRect; Spread* pSpread = pOurDoc->GetSelectedSpread(); if (pSpread==NULL) PasteRect = BoundingRect; else { // Try to make the pasteboard grow if necessary to include the new object position // This is very quick if the pasteboard is large enough already. pSpread->ExpandPasteboardToInclude(BoundingRect); // And re-read the bounding rectangle of the selection, as the pasteboard resize may have // caused the origin of our entire coordinate space to have moved! Argh! BoundingRect = pSel->GetBoundingRect(); // BoundingRect.Translate(dx,dy); // This is in Document Coords, so we need to convert it PasteRect = pSpread->GetPasteboardRect(); pSpread->DocCoordToSpreadCoord(&PasteRect); } // Assume the nudge will be OK. BOOL NudgeOK = TRUE; if (PasteRect.ContainsRect(BoundingRect)) { // Untranslated bounds fit inside pasteboard rect, so we must complain if the bounds // do not fit *after* translation // Translate the bounds by the nudge values BoundingRect.Translate(dx,dy); // Do the translated bounds still fit entirely in the pasteboard rect? NudgeOK = PasteRect.ContainsRect(BoundingRect); } else { // The original bounds overlap the pasteboard rect, so we must complain if the user // nudges the bounds completely out of sight if (PasteRect.IsIntersectedWith(BoundingRect)) { // The original bounds intersect with the pasteboard rect BoundingRect.Translate(dx,dy); // Only allow the nudge if the translated bounds still overlap with the spread. NudgeOK = PasteRect.IsIntersectedWith(BoundingRect); } } // If the nudge is OK, we may need to scroll the DocView? /* Jim, 12/9/96 - removed this because we don't want to scroll to show opn nudges if (NudgeOK) { DocCoord Coord(0,0); // If nudging left or right, pick the min or max X coord if (dx != 0) { if (dx < 0) Coord.x = BoundingRect.lox; else Coord.x = BoundingRect.hix; } // If nudging up or down, pick the max or min Y coord if (dy != 0) { if (dy < 0) Coord.y = BoundingRect.loy; else Coord.y = BoundingRect.hiy; } // If we have picked a coord, ensure that this coord is visible in the selected spread // of the selected DocView if (Coord != DocCoord(0,0)) { DocView* pDocView = DocView::GetSelected(); if (pDocView != NULL) pDocView->ScrollToShow(&Coord); } } */ return NudgeOK; }
void PathProcessorStrokeAirbrush::ProcessPath(Path *pPath, RenderRegion *pRender, PathShape ShapePath) { PORTNOTETRACE("other","PathProcessorStrokeAirbrush::ProcessPath - do nothing"); #ifndef EXCLUDE_FROM_XARALX ERROR3IF(pPath == NULL || pRender == NULL, "Illegal NULL Params"); // --- If the provided path is not stroked, then we'll just pass it straight through // We also don't touch it if we're doing EOR rendering, or click regions // BLOCK { StrokeColourAttribute *pStrokeColour = (StrokeColourAttribute *) pRender->GetCurrentAttribute(ATTR_STROKECOLOUR); if (pRender->DrawingMode != DM_COPYPEN || pRender->IsHitDetect() || !pPath->IsStroked || pStrokeColour == NULL || pStrokeColour->Colour.IsTransparent()) { pRender->DrawPath(pPath, this, ShapePath); return; } } // --- If the quality is set low, strokes are just rendered as centrelines // BLOCK { QualityAttribute *pQuality = (QualityAttribute *) pRender->GetCurrentAttribute(ATTR_QUALITY); if (pQuality != NULL && pQuality->QualityValue.GetLineQuality() != Quality::FullLine) { pRender->DrawPath(pPath, this, ShapePath); return; } } // --- If the attribute which created us is not the current StrokeType attribute, then // we have been overridden by a different stroke type, so we do nothing. // BLOCK { StrokeTypeAttrValue *pTypeAttr = (StrokeTypeAttrValue *) pRender->GetCurrentAttribute(ATTR_STROKETYPE); if (pTypeAttr != NULL && pTypeAttr != GetParentAttr()) { pRender->DrawPath(pPath, this, ShapePath); return; } } // --- Get the current line width from the render region // In case of failure, we initialise with suitable defaults INT32 LineWidth = 5000; // BLOCK { LineWidthAttribute *pWidthAttr = (LineWidthAttribute *) pRender->GetCurrentAttribute(ATTR_LINEWIDTH); if (pWidthAttr != NULL) LineWidth = pWidthAttr->LineWidth; } // Obtain an optimal number of steps for the line // When printing, we do heaps of steps to get top quality out the other end View *pView = pRender->GetRenderView(); ERROR3IF(pView == NULL, "No render view?!"); INT32 NumSteps = MaxAirbrushSteps; if (!pRender->IsPrinting()) GetNumSteps(pView, LineWidth); // --- Now, create a transparency mask bitmap for the airbrush Spread *pSpread = pRender->GetRenderSpread(); // ERROR3IF(pSpread == NULL, "No render spread!?"); // This can happen, rendering into a gallery // Get the render region's clip rectangle in Spread Coords. We don't need to // render anything bigger than this size, so it is the upper limit on our bitmap area. DocRect ClipRegion = pRender->GetClipRect(); // Intersect this with the path bounding rectangle to get the actual region we need to redraw // The smaller this is, the faster we go and the less memory we use. //DocRect PathRect = pPath->GetBoundingRect(); DocRect PathRect = pPath->GetBlobRect(); PathRect.Inflate(LineWidth); BOOL Intersects = ClipRegion.IsIntersectedWith(PathRect); if(!Intersects) { // Don't bother drawing anything - it's clipped out return; } ClipRegion = ClipRegion.Intersection(PathRect); // Round the ClipRegion edges up so they all lie exactly on screen pixel boundaries. // If we don't do this, then there can be a sub-pixel rounding error between the ClipRegion // and the actual bitmap size, so that the bitmap is scaled slightly when we plot it. // By making sure it's pixelised, we guarantee that the bitmap & clipregion are exactly equal sizes. // (It doesn't matter if the bitmap is a bit bigger than necessary) ClipRegion.Inflate(pRender->GetScaledPixelWidth()); ClipRegion.lo.Pixelise(pView); ClipRegion.hi.Pixelise(pView); // Get the current view's rendering matrix and view scale Matrix ConvMatrix = pRender->GetMatrix();//pView->ConstructRenderingMatrix(pSpread); FIXED16 ViewScale = pView->GetViewScale(); // Generate a 256-colour greyscale palette LOGPALETTE *pPalette = MakeGreyScalePalette(); if(pPalette == NULL) { pRender->DrawPath(pPath, this, ShapePath); return; } // Work out the DPI to use. Rather than just asking for PixelWidth or DPI from the // render region, we have to do a load of non-object-oriented stuff instead... double dpi = 96.0; if (pRender->IsPrinting()) { // we are printing, so ask the print options PrintControl *pPrintControl = pView->GetPrintControl(); if (pPrintControl != NULL) dpi = (double) pPrintControl->GetDotsPerInch(); } else if (IS_A(pRender, CamelotEPSRenderRegion)) { // Use DPI as set in EPS export options dialog. dpi = (double) EPSFilter::XSEPSExportDPI; } else { ERROR3IF(pRender->GetPixelWidth() <= 0, "Stupid (<1 millipoint) Pixel Width!"); if (pRender->GetPixelWidth() > 0) dpi = (double) (72000.0 / (double)pRender->GetPixelWidth()); } GRenderBitmap *pMaskRegion = new GRenderBitmap(ClipRegion, ConvMatrix, ViewScale, 8, dpi, pRender->IsPrinting(), XARADITHER_ORDERED_GREY, pPalette, FALSE); if (pMaskRegion == NULL) { pRender->DrawPath(pPath, this, ShapePath); return; } BOOL PathIsFilled = FALSE; // Will be set TRUE if this path should be filled at the bottom of the function //BLOCK { // Change the GDraw context in this render region so as to preserve the state // of the main render region. This is because GRenderRegions currently use // a single static GDrawContext! This also sets it up with a nice greyscale palette // so that we get the output we desire. pMaskRegion->UseGreyscaleContextDangerous(); // Attach our DC to the view and render region... if (pMaskRegion->AttachDevice(pView, NULL, pSpread)) { pMaskRegion->StartRender(); // We must save & restore the attribute state around all our rendering because // attributes otherwise stay on the renderstack until we delete the RndRgn, and as our // ones are on the program stack, they will have ceased to exist before then, which // makes for a wicked explosion. pMaskRegion->SaveContext(); ///////////////////////////////////////////////////////////////////////////////////// // --- Main Airbrush rendering loop // Make sure we've got an intensity function to use. This will create a new one if necessary ValueFunction *pvValueFunction = GetIntensityFunction(); if (pvValueFunction == NULL) { ERROR3("Failed to set an intensity function on an airbrush stroke"); pRender->DrawPath(pPath, this, ShapePath); return; } if(!RenderAirBrush(pPath, pMaskRegion, LineWidth, NumSteps, pvValueFunction, pRender, ShapePath)) { // Airbrush failed - just render the path without the airbrush effect pRender->DrawPath(pPath, this, ShapePath); return; } pMaskRegion->RestoreContext(); // --- ClipRect test code ///////////////////////////////////////////////////////////////////////////////////// // --- We have drawn the airbrushed stroke - now, if the path is filled, we // will render the filled area, so that in semi-transparent cases, the // stroke will not "show through" from behind the filled area. if (pPath->IsFilled) { ColourFillAttribute *pCFAttr = (ColourFillAttribute *) pRender->GetCurrentAttribute(ATTR_FILLGEOMETRY); if (pCFAttr != NULL && (!pCFAttr->Colour.IsTransparent() || pCFAttr->IsABitmapFill())) { PathIsFilled = TRUE; pMaskRegion->SaveContext(); ColourFillAttribute *pFillAttr = NULL; FillMappingAttribute *pMapAttr = NULL; // Obtain the object's transparent fill geometry TranspFillAttribute *pTransAttr = (TranspFillAttribute *) pRender->GetCurrentAttribute(ATTR_TRANSPFILLGEOMETRY); if (pTransAttr != NULL) { // Get a non-transparent version of the fill geometry pFillAttr = pTransAttr->MakeSimilarNonTranspFillGeometry(1.0); // Convert a fill mapping TranspFillMappingAttribute *pTransMapAttr = (TranspFillMappingAttribute *) pRender->GetCurrentAttribute(ATTR_TRANSPFILLMAPPING); if(pTransMapAttr != NULL) pMapAttr = pTransMapAttr->MakeSimilarNonTranspFillMapping(); } // Setup region and draw path into it if (pFillAttr != NULL) { pMaskRegion->SetFillGeometry(pFillAttr, TRUE); if(pMapAttr != NULL) pMaskRegion->SetFillMapping(pMapAttr, TRUE); } else pMaskRegion->SetFillColour(DocColour(0, 0, 0)); pMaskRegion->SetLineColour(DocColour(COLOUR_TRANS)); pMaskRegion->DrawPath(pPath, NULL, ShapePath); pMaskRegion->RestoreContext(); } } pMaskRegion->StopRender(); } pMaskRegion->StopUsingGreyscaleContextDangerous(); } // Extract the transparency mask bitmap from the render region OILBitmap *pOilBmp = pMaskRegion->ExtractBitmap(); // We no longer need the RenderRegion, so scrap it. delete pMaskRegion; pMaskRegion = NULL; pPalette = NULL; // Now, render a rectangle to the output render region, using the transparency mask if (pOilBmp == NULL) return; KernelBitmap *pMask = new KernelBitmap(pOilBmp, TRUE); if (pMask != NULL) { // Make sure the bitmap knows it's already a greyscale, else it will spend a lot of // time "converting" itself to a greyscale, and what's more, corrupting the grey levels // so that 255 (invisible) becomes 254 (slightly visible). Arrrrrgh! pMask->SetAsGreyscale(); // Create a transparency attribute from our mask bitmap BitmapTranspFillAttribute Trans; // We don't call pTrans->AttachBitmap because it seems to be stupid, and causes ructions // when we try to attach a temporary bitmap. We thus do the same thing, but avoiding // its attempts to automatically screw us about. Trans.BitmapRef.Detach(); Trans.BitmapRef.SetBitmap(pMask); Trans.SetStartPoint(&ClipRegion.lo); DocCoord EndPoint(ClipRegion.hi.x, ClipRegion.lo.y); Trans.SetEndPoint(&EndPoint); DocCoord EndPoint2(ClipRegion.lo.x, ClipRegion.hi.y); Trans.SetEndPoint2(&EndPoint2); UINT32 TValue = 0; Trans.SetStartTransp(&TValue); TValue = 255; Trans.SetEndTransp(&TValue); // Use the same transparency type as is set on the object being rendered (if any) { TranspFillAttribute *pTransAttr = (TranspFillAttribute *) pRender->GetCurrentAttribute(ATTR_TRANSPFILLGEOMETRY); if (pTransAttr != NULL) Trans.SetTranspType(pTransAttr->GetTranspType()); else Trans.SetTranspType(TT_Mix); // By default, we'll use Mix transparency } // --- OK, we finally got here! Render the stroke, using the transparency mask we just made pRender->SaveContext(); Trans.Render(pRender); // Render the path. If it is filled, then we render the entire thing (fill & stroke) using // the current fill geometry (to get a shadow/feather effect) if (PathIsFilled) { // Render the entire thing (fill & stroke) in one go. We render a rectangle over the cliprect // so that we do everything in one go (we can't render the fill &7 stroke separately, or // the transparency will overlap & it'll look wrong) pRender->SetLineColour(DocColour(COLOUR_TRANS)); // Don't render a line Path Rect; Rect.Initialise(); Rect.AddMoveTo(ClipRegion.lo); Rect.AddLineTo(DocCoord(ClipRegion.hix, ClipRegion.loy)); Rect.AddLineTo(ClipRegion.hi); Rect.AddLineTo(DocCoord(ClipRegion.lox, ClipRegion.hiy)); Rect.AddLineTo(ClipRegion.lo); Rect.IsFilled = TRUE; Rect.IsStroked = FALSE; pRender->DrawPath(&Rect, this, ShapePath); } else { // Otherwise, create a filled-outline path for the entire stroke, and render it // !!!!****ToDo - for now, strokes always render flat-filled with the stroke colour StrokeColourAttribute *pStrokeColour = (StrokeColourAttribute *) pRender->GetCurrentAttribute(ATTR_STROKECOLOUR); if (pStrokeColour != NULL) pRender->SetFillColour(pStrokeColour->Colour); // Fill the holes pRender->SetWindingRule(NonZeroWinding); Path *pOutput = CreateVarWidthStroke(pPath, pRender, LineWidth); if (pOutput != NULL) { pRender->DrawPath(pOutput, NULL, ShapePath); delete pOutput; pOutput = NULL; } } pRender->RestoreContext(); // Delete the kernel bitmap. This auto-deletes the OIL bitmap for us delete pMask; } #endif }
void OpAlign::DoWithParam(OpDescriptor* pOp, OpParam* pAlignParam) { // DMc alterations so that this works with compound nodes SelRange Selection(*(GetApplication()->FindSelection())); RangeControl rg = Selection.GetRangeControlFlags(); rg.PromoteToParent = TRUE; Selection.Range::SetRangeControl(rg); DocRect SelRect = Selection.GetBoundingRect(); DocRect TargetRect; TargetRect.MakeEmpty(); INT32 NumObjs = Selection.Count(); AlignParam* pAlign =(AlignParam*)pAlignParam; BOOL moved=FALSE; // set to TRUE if any object is moved BeginSlowJob(-1,FALSE); BOOL OK=DoStartTransOp(FALSE); // find parent spread of first object in selection Node* pFirstNode=NULL; Spread* pSpread =NULL; if (OK) { pFirstNode=Selection.FindFirst(); if (pFirstNode!=NULL) pSpread=pFirstNode->FindParentSpread(); OK=(pSpread!=NULL); if (!OK) ERROR2RAW("OpAlign::DoWithParam() - could not find parent spread"); } // Find the size of the target rectangle if (pAlign->target==ToSelection) TargetRect=SelRect; else { Page* pPage=pSpread->FindFirstPageInSpread(); while (pPage) { DocRect PageRect=pPage->GetPageRect(); if (pAlign->target==ToSpread || SelRect.IsIntersectedWith(PageRect)) TargetRect=TargetRect.Union(PageRect); pPage=pPage->FindNextPage(); } } // allocate all dynamic memory required Node** pObj=NULL; ObjInfo* x =NULL; ObjInfo* y =NULL; INT32* dx =NULL; INT32* dy =NULL; if (OK) ALLOC_WITH_FAIL(pObj,(Node**) CCMalloc(NumObjs*sizeof(Node*)), this); if (pObj!=NULL) ALLOC_WITH_FAIL(x, (ObjInfo*)CCMalloc(NumObjs*sizeof(ObjInfo)),this); if ( x!=NULL) ALLOC_WITH_FAIL(y, (ObjInfo*)CCMalloc(NumObjs*sizeof(ObjInfo)),this); if ( y!=NULL) ALLOC_WITH_FAIL(dx, (INT32*) CCMalloc(NumObjs*sizeof(INT32)), this); if ( dx!=NULL) ALLOC_WITH_FAIL(dy, (INT32*) CCMalloc(NumObjs*sizeof(INT32)), this); OK=(dy!=NULL); // if memory claimed OK and target rect not empty proceed with op // (ie. do nothing if 'within page(s)' when no object on a page) DocRect EmptyRect; if (OK && TargetRect!=EmptyRect) { // create an array of pointers to objects (nodes) to be affected Node* pNode=Selection.FindFirst(); INT32 i=0; while (pNode!=NULL) { if (pNode->IsBounded() && !((NodeRenderableBounded*)pNode)->GetBoundingRect(TRUE).IsEmpty()) pObj[i++]=pNode; pNode=Selection.FindNext(pNode); } NumObjs=i; // cache x & y info in separate arrays so they can be sorted separately XLONG SumObjWidths =0; XLONG SumObjHeights=0; for (i=0; i<NumObjs; i++) { DocRect ObjRect=((NodeRenderableBounded*)pObj[i])->GetBoundingRect(); x[i].i=i; x[i].lo=ObjRect.lo.x; x[i].hi=ObjRect.hi.x; SumObjWidths+=ObjRect.hi.x-ObjRect.lo.x; y[i].i=i; y[i].lo=ObjRect.lo.y; y[i].hi=ObjRect.hi.y; SumObjHeights+=ObjRect.hi.y-ObjRect.lo.y; } // for each object, calculate the x and y displacements independently AlignOneAxis(pAlign->h,NumObjs,SumObjWidths, TargetRect.lo.x,TargetRect.hi.x,x,dx); AlignOneAxis(pAlign->v,NumObjs,SumObjHeights,TargetRect.lo.y,TargetRect.hi.y,y,dy); // apply the x and y displacements simultaneously to each object for (i=0; i<NumObjs; i++) if (dx[i]!=0 || dy[i]!=0) { moved=TRUE; Trans2DMatrix* pMatrix=new Trans2DMatrix(dx[i],dy[i]); DoTransformNode((NodeRenderableInk*)pObj[i],pMatrix); } } // free up any memory which was allocated CCFree(dx); CCFree(dy); CCFree(x); CCFree(y); CCFree(pObj); if (moved) { Document::GetSelected()->ForceRedraw(pSpread, TargetRect); GetApplication()->UpdateSelection(); } else FailAndExecute(); End(); EndSlowJob(); }