Example #1
0
void ImagemapRenderRegion::AddPathToImagemap(Path* ppthToAdd, WebAddressAttribute* pwaaCurrent)
{
	//First get the origin of the export area and the DPI
	DocCoord dcOrigin=ImagemapFilterOptions::GetOriginOfExportArea(m_Options.m_stExportArea);
	double dDPI=m_Options.m_dDPI;

	//Now, how many subpaths are there in this path?
	INT32 lNumSubpaths=ppthToAdd->GetNumSubpaths();

	//For each subpath in the path
	for (INT32 l=0; l<lNumSubpaths; l++)
	{
		//Create a new path
		Path pthSubpath;

		pthSubpath.Initialise(ppthToAdd->GetNumCoords());

		//And copy the next subpath into it
		ppthToAdd->MakePathFromSubPath(l, &pthSubpath);

		//Now, if that subpath is closed
		if (pthSubpath.IsSubPathClosed(0))
		{
			//Then we want to add it to the imagemap

			//So scale it to dDPI and by dcOrigin
			pthSubpath.Scale(dcOrigin, dDPI);
	
			//Now we need to flatten it.
			//This means creating a new path, because otherwise Path::Flatten
			//goes wrong

			Path pthFlattened;

			pthFlattened.Initialise(pthSubpath.GetNumCoords());

			//So, if we should flatten the path
			if (m_Options.m_ffApprox!=FF_NOTATALL)
				//Then do it
				pthSubpath.Flatten(m_Options.m_ffApprox, &pthFlattened);
			else
				//Otherwise, simply copy the path across
				pthFlattened.CopyPathDataFrom(&pthSubpath);

			//Then add the flattened path to the imagemap
			m_Imagemap.AddPolygon(&pthFlattened, pwaaCurrent->m_url.GetWebAddress(), pwaaCurrent->m_pcFrame);
		}
	}
			
	
}
Example #2
0
void MouldGeometry::MouldPathRender(Path* pPath, RenderRegion* pRegion)
{
	Path RenderPath;
	if (!(RenderPath.Initialise(12,12))) return;
	if (!MouldPathToPath(pPath,&RenderPath)) return;

	pRegion->DrawPath(&RenderPath);
}
Example #3
0
DocRect ArrowRec::FindBoundsAt(const DocCoord& ArrowCentre, const DocCoord& Direction, 
							   INT32 ParentLineWidth)
{
	DocRect Bounds(0,0,0,0);

	// Find a matrix to transform the ArrowHead to this Position.
	Trans2DMatrix Trans;
	GetArrowMatrix(ArrowCentre, Direction, ParentLineWidth, &Trans);

	// Note:
	// We should really be able to ask Gavin to Calculate the Bounds,
	// and pass him this Transform Matrix, but he can't do this at the
	// moment, so we'll have to actually transform the path into
	// a tempory path, and then ask him to calc the bounds of that.

	// Make a tempory path to transform
	Path* TransPath = new Path();
	if (TransPath == NULL)
		return Bounds;

	// Copy the path data from the ArrorHead into our tempory path.
	BOOL 	ok = TransPath->Initialise(ArrowShape->GetNumCoords());
	if (ok) ok = TransPath->CopyPathDataFrom(ArrowShape);

	if (!ok)
	{
		// Tidy up if we failed
		delete TransPath;
		return Bounds;
	}

	// Go transform the Tempory path
	Trans.Transform(TransPath->GetCoordArray(), 
					TransPath->GetNumCoords() );

	BOOL GDrawResult = FALSE;
	
	// Find out what the paths bounding rect is, taking into account
	// any bezier curve thingies. 

	GDrawContext *GD = GRenderRegion::GetStaticDrawContext();
	
	if (GD != NULL)
		GDrawResult = GD->CalcStrokeBBox((POINT*)TransPath->GetCoordArray(),
											TransPath->GetVerbArray(), TransPath->GetNumCoords(),
											(RECT *)(&Bounds),
											TRUE, 0, CAPS_ROUND, JOIN_ROUND, NULL) == 0;

	// If Gavin failed, then use backup technique of getting coord array bounds
	if (!GDrawResult)
		Bounds = TransPath->GetBoundingRect();

	// Delete the temporary transformed path
	delete TransPath;

	return Bounds;
}
Example #4
0
void ImagemapRenderRegion::AddCircleToImagemap(Path* ppthToScale, WebAddressAttribute* pwaaCurrent)
{
	//First get the origin of the export area and the DPI
	DocCoord dcOrigin=ImagemapFilterOptions::GetOriginOfExportArea(m_Options.m_stExportArea);
	double dDPI=m_Options.m_dDPI;

	//Now make a copy of the path
	Path pthToAdd;
	
	pthToAdd.Initialise(ppthToScale->GetNumCoords());

	pthToAdd.CopyPathDataFrom(ppthToScale);

	//Scale it
	pthToAdd.Scale(dcOrigin, dDPI);

	//And add it to the imagemap
	m_Imagemap.AddCircle(&pthToAdd, pwaaCurrent->m_url.GetWebAddress(), pwaaCurrent->m_pcFrame);
	
}
Example #5
0
BOOL ArrowRec::CreateStockArrow(StockArrow ArrowType)
{
	if (ArrowShape != NULL)
	{
		delete ArrowShape;
		ArrowShape = NULL;
	}

	BOOL ok;
	Path* pPath;

	const INT32 Size  = 3;
	const INT32 Width = (72000/2)*3;

	if (ArrowType >= NUM_STOCK_ARROWS)
		ArrowType = SA_STRAIGHTARROW;

	// Set the ArrowID
	ArrowID = ArrowType;

	switch (ArrowType)
	{
		case SA_STRAIGHTARROW:

			/*
			STRAIGHT
			-9 54 m
			-9 0 l
			-9 -54 l
			117 0 l
			-9 54 l
			-9 54 l
			*/

			pPath = new Path();
			if (pPath == NULL)
				return FALSE;

			ok = pPath->Initialise(4);
			if (ok) 	 pPath->FindStartOfPath();
			if (ok) ok = pPath->InsertMoveTo(DocCoord( -9000,  54000));
			if (ok) ok = pPath->InsertLineTo(DocCoord( -9000, -54000));
			if (ok) ok = pPath->InsertLineTo(DocCoord(117000,      0));
			if (ok) ok = pPath->CloseSubPath();

			if (!ok)
			{
				delete pPath;
				return FALSE;
			}

			pPath->IsFilled  = TRUE;
			pPath->IsStroked = FALSE;

			ArrowShape 	= pPath;
			Centre 		= DocCoord(0,0);
			LineWidth 	= Width;
			ArrowWidth 	= INT32(Size);
			ArrowHeight = INT32(Size);
 			IsNull 		= FALSE;

			StartArrow = FALSE;

			break;

		case SA_ANGLEDARROW:

			/*
			ANGLED
			-26.999 53.999 m
			-9 0 l
			-26.999 -54.001 l
			135 0 l
			-26.999 53.999 l
			*/

			pPath = new Path();
			if (pPath == NULL)
				return FALSE;

			ok = pPath->Initialise(5);
			if (ok) 	 pPath->FindStartOfPath();
			if (ok) ok = pPath->InsertMoveTo(DocCoord(-27000,  54000));
			if (ok) ok = pPath->InsertLineTo(DocCoord( -9000,      0));
			if (ok) ok = pPath->InsertLineTo(DocCoord(-27000, -54000));
			if (ok) ok = pPath->InsertLineTo(DocCoord(135000,      0));
			if (ok) ok = pPath->CloseSubPath();

			if (!ok)
			{
				delete pPath;
				return FALSE;
			}

			pPath->IsFilled  = TRUE;
			pPath->IsStroked = FALSE;

			ArrowShape 	= pPath;
			Centre 		= DocCoord(0,0);
			LineWidth 	= Width;
			ArrowWidth 	= INT32(Size);
			ArrowHeight = INT32(Size);
 			IsNull 		= FALSE;

			StartArrow = FALSE;

			break;


		case SA_ROUNDEDARROW:

			/*
			ROUND
			-9 0 m
			-9 -45 l
			-9 -51.708 2.808 -56.580 9 -54 c
			117 -9 l
			120.916 -7.369 126 -4.242 126 0 c
			126 4.242 120.916 7.369 117 9 c
			9 54 l
			2.808 56.580 -9 51.708 -9 45 c
			-9 0 l
			*/

			pPath = new Path();
			if (pPath == NULL)
				return FALSE;

			ok = pPath->Initialise(17);
			if (ok) 	 pPath->FindStartOfPath();
			if (ok) ok = pPath->InsertMoveTo( DocCoord(  -9000,      0));
			if (ok) ok = pPath->InsertLineTo( DocCoord(  -9000, -45000));
			if (ok) ok = pPath->InsertCurveTo(DocCoord(  -9000, -51708),
											  DocCoord(   2808, -56580),
											  DocCoord(   9000, -54000));
			if (ok) ok = pPath->InsertLineTo( DocCoord( 117000,  -9000));
			if (ok) ok = pPath->InsertCurveTo(DocCoord( 120916,  -7369),
											  DocCoord( 126000,  -4242),
											  DocCoord( 126000,      0));
			if (ok) ok = pPath->InsertCurveTo(DocCoord( 126000,   4242),
											  DocCoord( 120916,   7369),
											  DocCoord( 117000,   9000));
			if (ok) ok = pPath->InsertLineTo( DocCoord(   9000,  54000));
			if (ok) ok = pPath->InsertCurveTo(DocCoord(   2808,  56580),
											  DocCoord(  -9000,  51708),
											  DocCoord(  -9000,  45000));
			if (ok) ok = pPath->CloseSubPath();

			if (!ok)
			{
				delete pPath;
				return FALSE;
			}

			pPath->IsFilled  = TRUE;
			pPath->IsStroked = FALSE;

			ArrowShape 	= pPath;
			Centre 		= DocCoord(0,0);
			LineWidth 	= Width;
			ArrowWidth 	= INT32(Size);
			ArrowHeight = INT32(Size);
 			IsNull 		= FALSE;

			StartArrow = FALSE;

			break;
	

		case SA_SPOT:

			/*
			BLOB
			-54 0 m
			-54 29.807 -29.807 54 0 54 c
			29.807 54 54 29.807 54 0 c
			54 -29.807 29.807 -54 0 -54 c
			-29.807 -54 -54 -29.807 -54 0 c
			*/

			pPath = new Path();
			if (pPath == NULL)
				return FALSE;

			ok = pPath->Initialise(14);
			if (ok) 	 pPath->FindStartOfPath();
			if (ok) ok = pPath->InsertMoveTo( DocCoord( -54000,      0));
			if (ok) ok = pPath->InsertCurveTo(DocCoord( -54000,  29807),
											  DocCoord( -29807,  54000),
											  DocCoord(      0,  54000));
			if (ok) ok = pPath->InsertCurveTo(DocCoord(  29807,  54000),
											  DocCoord(  54000,  29807),
											  DocCoord(  54000,      0));
			if (ok) ok = pPath->InsertCurveTo(DocCoord(  54000, -29807),
											  DocCoord(  29807, -54000),
											  DocCoord(      0, -54000));
			if (ok) ok = pPath->InsertCurveTo(DocCoord( -29807, -54000),
											  DocCoord( -54000, -29807),
											  DocCoord( -54000,      0));
			if (ok) ok = pPath->CloseSubPath();

			if (!ok)
			{
				delete pPath;
				return FALSE;
			}

			pPath->IsFilled  = TRUE;
			pPath->IsStroked = FALSE;

			ArrowShape 	= pPath;
			Centre 		= DocCoord(0,0);
			LineWidth 	= Width;
			ArrowWidth 	= INT32(Size);
			ArrowHeight = INT32(Size);
 			IsNull 		= FALSE;

			StartArrow = TRUE;

			break;
	

		case SA_DIAMOND:

			/*
			DIAMOND
			-63 0 m
			0 63 l
			63 0 l
			0 -63 l
			-63 0 l
			*/

			pPath = new Path();
			if (pPath == NULL)
				return FALSE;

			ok = pPath->Initialise(5);
			if (ok) 	 pPath->FindStartOfPath();
			if (ok) ok = pPath->InsertMoveTo(DocCoord(-63000,      0));
			if (ok) ok = pPath->InsertLineTo(DocCoord(     0,  63000));
			if (ok) ok = pPath->InsertLineTo(DocCoord( 63000,      0));
			if (ok) ok = pPath->InsertLineTo(DocCoord(     0, -63000));
			if (ok) ok = pPath->CloseSubPath();

			if (!ok)
			{
				delete pPath;
				return FALSE;
			}

			pPath->IsFilled  = TRUE;
			pPath->IsStroked = FALSE;

			ArrowShape 	= pPath;
			Centre 		= DocCoord(0,0);
			LineWidth 	= Width;
			ArrowWidth 	= INT32(Size);
			ArrowHeight = INT32(Size);
 			IsNull 		= FALSE;

			StartArrow = TRUE;

			break;
	
		case SA_ARROWFEATHER:

			/*
			FEATHER
			18 -54 m
			108 -54 l
			63 0 l
			108 54 l
			18 54 l
			-36 0 l
			18 -54 l
			*/

			pPath = new Path();
			if (pPath == NULL)
				return FALSE;

			ok = pPath->Initialise(7);
			if (ok) 	 pPath->FindStartOfPath();
			if (ok) ok = pPath->InsertMoveTo(DocCoord( 18000, -54000));
			if (ok) ok = pPath->InsertLineTo(DocCoord(108000, -54000));
			if (ok) ok = pPath->InsertLineTo(DocCoord( 63000,      0));
			if (ok) ok = pPath->InsertLineTo(DocCoord(108000,  54000));
			if (ok) ok = pPath->InsertLineTo(DocCoord( 18000,  54000));
			if (ok) ok = pPath->InsertLineTo(DocCoord(-36000,      0));
			if (ok) ok = pPath->CloseSubPath();

			if (!ok)
			{
				delete pPath;
				return FALSE;
			}

			pPath->IsFilled  = TRUE;
			pPath->IsStroked = FALSE;

			ArrowShape 	= pPath;
			Centre 		= DocCoord(0,0);
			LineWidth 	= Width;
			ArrowWidth 	= INT32(Size);
			ArrowHeight = INT32(Size);
 			IsNull 		= FALSE;

			StartArrow = TRUE;

			break;
	
		case SA_ARROWFEATHER2:

			/*
			FEATHER3
			-35.998 0 m
			18 -54 l
			54 -54 l
			18 -18 l
			27 -18 l
			63 -54 l
			99 -54 l
			63 -18 l
			72 -18 l
			108 -54 l
			144 -54 l
			90 0 l
			144 54 l
			108 54 l
			72 18 l
			63 18 l
			99 54 l
			63 54 l
			27 18 l
			18 18 l
			54 54 l
			18 54 l
			-35.998 0 l
			*/

			pPath = new Path();
			if (pPath == NULL)
				return FALSE;

			ok = pPath->Initialise(23);
			if (ok) 	 pPath->FindStartOfPath();
			if (ok) ok = pPath->InsertMoveTo(DocCoord( -36000,      0));
			if (ok) ok = pPath->InsertLineTo(DocCoord(  18000, -54000));
			if (ok) ok = pPath->InsertLineTo(DocCoord(  54000, -54000));
			if (ok) ok = pPath->InsertLineTo(DocCoord(  18000, -18000));
			if (ok) ok = pPath->InsertLineTo(DocCoord(  27000, -18000));
			if (ok) ok = pPath->InsertLineTo(DocCoord(  63000, -54000));
			if (ok) ok = pPath->InsertLineTo(DocCoord(  99000, -54000));
			if (ok) ok = pPath->InsertLineTo(DocCoord(  63000, -18000));
			if (ok) ok = pPath->InsertLineTo(DocCoord(  72000, -18000));
			if (ok) ok = pPath->InsertLineTo(DocCoord( 108000, -54000));
			if (ok) ok = pPath->InsertLineTo(DocCoord( 144000, -54000));
			if (ok) ok = pPath->InsertLineTo(DocCoord(  90000,      0));
			if (ok) ok = pPath->InsertLineTo(DocCoord( 144000,  54000));
			if (ok) ok = pPath->InsertLineTo(DocCoord( 108000,  54000));
			if (ok) ok = pPath->InsertLineTo(DocCoord(  72000,  18000));
			if (ok) ok = pPath->InsertLineTo(DocCoord(  63000,  18000));
			if (ok) ok = pPath->InsertLineTo(DocCoord(  99000,  54000));
			if (ok) ok = pPath->InsertLineTo(DocCoord(  63000,  54000));
			if (ok) ok = pPath->InsertLineTo(DocCoord(  27000,  18000));
			if (ok) ok = pPath->InsertLineTo(DocCoord(  18000,  18000));
			if (ok) ok = pPath->InsertLineTo(DocCoord(  54000,  54000));
			if (ok) ok = pPath->InsertLineTo(DocCoord(  18000,  54000));
			if (ok) ok = pPath->CloseSubPath();

			if (!ok)
			{
				delete pPath;
				return FALSE;
			}

			pPath->IsFilled  = TRUE;
			pPath->IsStroked = FALSE;

			ArrowShape 	= pPath;
			Centre 		= DocCoord(0,0);
			LineWidth 	= Width;
			ArrowWidth 	= INT32(Size);
			ArrowHeight = INT32(Size);
 			IsNull 		= FALSE;

			StartArrow = TRUE;

			break;
	
		case SA_HOLLOWDIAMOND:

			/*
			HOLLOW
			0 45 m
			-45 0 l
			0 -45 l
			45 0 l
			0 45 l
			0 63 m
			-63 0 l
			0 -63 l
			63 0 l
			0 63 l
			*/

			pPath = new Path();
			if (pPath == NULL)
				return FALSE;

			ok = pPath->Initialise(10);
			if (ok) 	 pPath->FindStartOfPath();
			if (ok) ok = pPath->InsertMoveTo(DocCoord(     0,  45000));
			if (ok) ok = pPath->InsertLineTo(DocCoord(-45000,      0));
			if (ok) ok = pPath->InsertLineTo(DocCoord(     0, -45000));
			if (ok) ok = pPath->InsertLineTo(DocCoord( 45000,      0));
			if (ok) ok = pPath->CloseSubPath();
			if (ok) ok = pPath->InsertMoveTo(DocCoord(     0,  63000));
			if (ok) ok = pPath->InsertLineTo(DocCoord(-63000,      0));
			if (ok) ok = pPath->InsertLineTo(DocCoord(     0, -63000));
			if (ok) ok = pPath->InsertLineTo(DocCoord( 63000,      0));
			if (ok) ok = pPath->CloseSubPath();

			if (!ok)
			{
				delete pPath;
				return FALSE;
			}

			pPath->IsFilled  = TRUE;
			pPath->IsStroked = FALSE;

			ArrowShape 	= pPath;
			Centre 		= DocCoord(-45000,0);
			LineWidth 	= Width;
			ArrowWidth 	= INT32(Size);
			ArrowHeight = INT32(Size);
 			IsNull 		= FALSE;

			StartArrow = TRUE;

			break;

		default:
			ArrowShape 	= NULL;
			Centre 		= DocCoord(0,0);

			LineWidth	= DEFAULT_ARROW_LINEWIDTH;
			ArrowWidth	= 3;
			ArrowHeight	= 3;

			StartArrow 			= FALSE;
			ScaleWithLineWidth 	= TRUE;
			ArrowID 			= SA_NULLARROW;
 			IsNull 				= TRUE;
			break;
	}

	return TRUE;
}
Example #6
0
BOOL StringToBitmap::TTFAddString(String_256 *text, UINT32 Xsize, UINT32 Ysize, UINT32 DPI, PLOGFONT pLogFont,
                                  INT32 IntLeading, KernelBitmap **BM, UINT32 ForeColour)
{
    KernelBitmap *Bitmap = *BM;

    /*	HDC ScreenDC = CreateCompatibleDC(NULL);
    	if (ScreenDC == NULL)
    	{
    		ERROR3("StringToBitmap::AddString: Unable to create screen DC");
    		return FALSE;
    	}*/

    CDC SysDisplay;
    BOOL ok=SysDisplay.CreateCompatibleDC(NULL);
    if(!ok)
    {
        //DeleteDC(ScreenDC);
        ERROR3("StringToBitmap::TTF AddString: Unable to create CDC");
        return FALSE;
    }

    HDC ScreenDC = SysDisplay.m_hDC;

    // bodge to get things working with GetBezierFromChar
    INT32 OldlfHeight = pLogFont->lfHeight;
    pLogFont->lfHeight = -(pLogFont->lfHeight - IntLeading);

    UINT32 CurrentPathSizeAlloc = 0;
    Trans2DMatrix *pTransform = NULL;
    DocCoord *pPathCoords = NULL;

    Path *pPath = NULL;
    //pPath = new Path();

    DocCoord *pPolyCordBuffer = NULL;
    PathVerb *pPolyVerbBuffer = NULL;
    UINT32 TextLength = (UINT32)text->Length();
    SIZE StringSize= {0,0};

    // Get handle of font

//	HFONT hNewFont = CreateFontIndirect(pLogFont);
//	HGDIOBJ hOldFont = SelectObject(ScreenDC, hNewFont);

    CFont UnHintedCFont;
    if(!UnHintedCFont.CreateFontIndirect(pLogFont))
    {
        SysDisplay.DeleteDC();
        pLogFont->lfHeight = OldlfHeight;
        return FALSE;
    }

    CFont* pOldCFont=SysDisplay.SelectObject(&UnHintedCFont);

    // Get the default character to use if a charater is not present in the font.
    WCHAR FontDefaultCharacter = (unsigned char)'?';
    TEXTMETRIC FontTextData;
#ifdef _UNCCODE
    if (SysDisplay.GetTextMetrics(&FontTextData))
        FontDefaultCharacter = FontTextData.tmDefaultChar;
#else
    if (SysDisplay.GetTextMetrics(&FontTextData))
        FontDefaultCharacter = (unsigned char)FontTextData.tmDefaultChar;
#endif

    // Work out a nice scaling factor so the font fits in the bitmap ok...

    // Not 32 ?
    GetTextExtentPoint(ScreenDC, *text, TextLength, &StringSize);

    if(StringSize.cy == 0)
    {
        SysDisplay.SelectObject(pOldCFont);
        SysDisplay.DeleteDC();
        pLogFont->lfHeight = OldlfHeight;
        return FALSE;
    }

    //ERROR3IF(!ok, "Initial GetTextExtentPoint32() failed");
    double YScale = ((double)Ysize / (double)StringSize.cy) / (double)2;
    double XScale = YScale;

    // Shift thumbnail upwards, and scale down a bit - to get the g's looking right
    // One or two fonts require this reducing (their tops are clipped), 72000/100 is
    // about right for most of them though...
    // Note the external previews were done with 72000/220 for Matrix and 72000/140 for
    // the capital only fonts.
    double YShift = 72000/100;//72000/80;

    YScale = (YScale * 78) / 100;
    XScale = (XScale * 78) / 100;

    if(!text->IsEmpty())
    {
        const TCHAR* pCurrentChar = (const TCHAR*)(*text);

        while (ok && *pCurrentChar!=0)
        {
            // Get the current character as Unicode.
#ifdef _UNICODE
            WCHAR wchr = *pCurrentChar;		// pCurrentChar is a pointer to WCHAR in _UNICODE builds
#else
            UINT32 CharToConvert = 0;
            if (UnicodeManager::IsDBCSLeadByte(*pCurrentChar))
                CharToConvert = UnicodeManager::ComposeMultiBytes(*pCurrentChar, *(pCurrentChar+1));
            else
                CharToConvert = (unsigned char)(*pCurrentChar);
            WCHAR wchr = UnicodeManager::MultiByteToUnicode(CharToConvert);
#endif

            // Get positioning information for this character
            ok = GetTextExtentPoint(ScreenDC, *text, (pCurrentChar-(TCHAR*)(*text)), &StringSize);
            ERROR3IF(!ok, "GetTextExtentPoint32() failed");
            if (!ok) break;

            // Get the characters path
            DWORD PathSize = 0;
            ok = TextManager::GetBezierFromChar(&SysDisplay, wchr, pLogFont, &PathSize, (POINT *)NULL, (BYTE *)NULL);
            if (!ok)
            {
                wchr = FontDefaultCharacter;
                ok = TextManager::GetBezierFromChar(&SysDisplay, wchr, pLogFont, &PathSize, (POINT *)NULL, (BYTE *)NULL);
            }
            ERROR3IF(!ok, "GetBezierFromChar returned false");
            if (!ok) break;

            // Pointer to an array of path coordinates
            if(pPolyCordBuffer == NULL)
            {
                TRY
                {
                    pPolyCordBuffer = new DocCoord[PathSize];
                }
                CATCH (CMemoryException, e)
                {
                    pPolyCordBuffer = NULL;
                    /*ERROR(_R(IDS_OUT_OF_MEMORY), FALSE);*/
                }
                END_CATCH
            }

            // Pointer to an array of path verbs
            if(pPolyVerbBuffer == NULL)
            {
                TRY
                {
                    pPolyVerbBuffer = new PathVerb[PathSize];
                }
                CATCH (CMemoryException, e)
                {
                    pPolyVerbBuffer = NULL;
                    /*ERROR(_R(IDS_OUT_OF_MEMORY), FALSE);*/
                }
                END_CATCH
            }

            if (pPolyCordBuffer == NULL || pPolyVerbBuffer == NULL)
            {
                ok = FALSE;
                break;
            }

            CurrentPathSizeAlloc = PathSize;

            // Fill up the buffers until they're bursting with fontyness
            ok = TextManager::GetBezierFromChar(&SysDisplay, wchr, pLogFont, &PathSize, (POINT *)pPolyCordBuffer,
                                                (BYTE *)pPolyVerbBuffer);
            if(!ok) TRACEUSER( "Richard", _T("GetBezierFromChar returned false in second phase...\n"));
            if(!ok)	break;

            // Spaces set PathSize to zero
            if((PathSize > 0)/* && (pPath != NULL)*/)
            {
                pPath = new Path();
                pPath->Initialise(PathSize, 12);
                pPath->CopyPathDataFrom(pPolyCordBuffer, pPolyVerbBuffer, PathSize, TRUE);

                // Major bodge at present with the x spacing...
                Matrix scale(XScale, 0, 0, YScale, (INT32)((XScale*StringSize.cx*72000)/(double)DPI), (INT32)YShift);

                pTransform = new Trans2DMatrix(scale);
                pPathCoords = pPath->GetCoordArray();
                pTransform->Transform( pPathCoords, pPath->GetNumCoords() );
                delete pTransform;

                pPath->InitialiseFlags();

                ok = ALU->GradFillPath(pPath, ForeColour, ForeColour, 0, 0, 0,/*Xsize/2,*/ Ysize, S2BMP_ANTIALIAS);
                ERROR3IF(!ok, "Gradfillpath returned false");
                if(!ok)	break;

                delete pPath;
            }

            // S2BMP_MAGIC is the worderfully fabby constant that mark's getbezierfromchar returns
            // Theory goes that he's going to sort this out sometime...
            if(CurrentPathSizeAlloc != S2BMP_MAGIC)
            {
                delete []pPolyCordBuffer;
                delete []pPolyVerbBuffer;

                pPolyCordBuffer = NULL;
                pPolyVerbBuffer = NULL;
                CurrentPathSizeAlloc = 0;
            }

            pPath = NULL;
            pTransform = NULL;

            pCurrentChar = camStrinc(pCurrentChar);
        }
Example #7
0
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
}
Example #8
0
void PathProcessorStrokeVector::ProcessPath(Path *pPath,
											RenderRegion *pRender,
											PathShape ShapePath)
{
	PORTNOTETRACE("other","PathProcessorStrokeVector::ProcessPath - do nothing");
#ifndef EXCLUDE_FROM_XARALX
	ERROR3IF(pPath == NULL || pRender == NULL, "Illegal NULL Params");

	// Get the RenderRegion SubRenderContext and see if we're returning part-way through a background render
	VectorStrokeSubRenderContext *pSubRenderContext = (VectorStrokeSubRenderContext *)pRender->GetSubRenderState();
	if (pSubRenderContext != NULL && !IS_A(pSubRenderContext, VectorStrokeSubRenderContext))
	{
		// We can't use the sub render context, because it's not ours!
		pSubRenderContext = NULL;
	}

	// --- If we don't have a valid stroke definition, then get the base class to render
	// the stroke as a simple flat-filled stroke.
	StrokeDefinition *pStrokeDef = StrokeComponent::FindStroke(StrokeID);
	if (pStrokeDef == NULL)
	{
		PathProcessorStroke::ProcessPath(pPath, pRender);
		return;
	}

	// --- See if we have to create a new SubRenderContext, or if we can use the one passed in.
	// We always store all relevant variables in a SubRenderContext object so that we can easily
	// return control to the RenderRegion without having to copy lots of local values in/out.
	const BOOL CreateSubRenderContext = (pSubRenderContext == NULL);
	if (CreateSubRenderContext)
	{
		pSubRenderContext = new VectorStrokeSubRenderContext;
		if (pSubRenderContext == NULL)
		{
			pRender->DrawPath(pPath, this, ShapePath);
			return;
		}

		// --- 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 hit detection
		if (!pPath->IsStroked || pRender->DrawingMode != DM_COPYPEN || pRender->IsHitDetect())
		{
			delete pSubRenderContext;
			pRender->DrawPath(pPath, this, ShapePath);
			return;
		}

		// --- If the quality is set low, or if the current stroke attribute is not our "parent"
		// attribute (so we're not the "current" stroker) then strokes are just rendered as centrelines
		// BLOCK
		{
			QualityAttribute *pQuality = (QualityAttribute *) pRender->GetCurrentAttribute(ATTR_QUALITY);
			StrokeTypeAttrValue *pTypeAttr = (StrokeTypeAttrValue *) pRender->GetCurrentAttribute(ATTR_STROKETYPE);

			if ((pQuality != NULL && pQuality->QualityValue.GetLineQuality() != Quality::FullLine) ||
				(pTypeAttr != NULL && pTypeAttr != GetParentAttr()))
			{
				delete pSubRenderContext;
				pRender->DrawPath(pPath, this, ShapePath);
				return;
			}
		}

		// --- We don't expect the input path to be stroked AND filled on entry
		ERROR3IF(pPath->IsFilled, "PathProcessor expected RenderRegion to handle IsFilled case");

		// --- Get the current line width & Join Style from the render region
		// BLOCK
		{
			LineWidthAttribute *pWidthAttr = (LineWidthAttribute *) pRender->GetCurrentAttribute(ATTR_LINEWIDTH);
			if (pWidthAttr != NULL)
				pSubRenderContext->LineWidth = pWidthAttr->LineWidth;

			JoinTypeAttribute *pJoinAttr = (JoinTypeAttribute *) pRender->GetCurrentAttribute(ATTR_JOINTYPE);
			if (pJoinAttr != NULL)
				pSubRenderContext->JoinStyle = pJoinAttr->JoinType;
		}
	}

	// --- Create a new path to be rendered in place of the provided path
	// Note that I use a large allocation size so that reallocation need not be done
	// frequently, which also helps reduce memory fragmentation.
	Path *pOutput = new Path;
	if (pOutput == NULL)
	{
		if (!pRender->IsSubRenderStateLocked())
			pRender->SetSubRenderState(NULL);
		delete pSubRenderContext;
		pRender->DrawPath(pPath, this, ShapePath);
		return;
	}

	pOutput->Initialise(128, 128);


	// --- Find our Variable Width function
	if (CreateSubRenderContext)
	{
		// --- Get the variable line width descriptor from the render region
		VariableWidthAttrValue *pVarWidthAttr = (VariableWidthAttrValue *) pRender->GetCurrentAttribute(ATTR_VARWIDTH);
		if (pVarWidthAttr != NULL)
			pSubRenderContext->pValFunc = pVarWidthAttr->GetWidthFunction();
	}

	ValueFunction *pValFunc = pSubRenderContext->pValFunc;

	// If we couldn't find a proper value function, then we'll default to constant-width.
	// We keep a static Constant function around always, because it's thread-safe and because
	// that saves us the overhead of creating and deleting it on the stack each time we're called
	static ValueFunctionConstant Constant(1.0);
	if (pValFunc == NULL)
		pValFunc = &Constant;


	// --- Find our brush clipart tree
	Node *pBrush = pStrokeDef->GetStrokeTree();
	ERROR3IF(!IS_A(pBrush, Spread), "Brush does not start with a Spread Node!");
	DocRect BrushBounds = ((Spread *)pBrush)->GetBoundingRect();

	// Get a PathStroker to map paths onto the destination stroke with
	PathStrokerVector Stroker(pValFunc, pSubRenderContext->LineWidth,
								LineCapButt, &BrushBounds);

	// Work out if this is a repeating stroke, and if so, how often it repeats
	if (CreateSubRenderContext)
	{
		if (pStrokeDef->IsRepeating())
		{
			// The repeat distance is calculated as a number of millipoints per repeat of the
			// stroke, such that it retains the correct aspect ratio. That is, the ratio of
			// brush width to height is the same as RepeatDist to LineWidth
			pSubRenderContext->RepeatDist = (INT32) (Stroker.GetScaleFactor() * (double)BrushBounds.Width());
			if (pSubRenderContext->RepeatDist < 1000)		// I absolutely refuse to repeat it more than
				pSubRenderContext->RepeatDist = 1000;		// once every 1pt, as this is plenty small enough

			// Suss the path length out
			ProcessLength GenerateLength(100);
			double Length = 0;
			BOOL ok = GenerateLength.PathLength(pPath, &Length);

			// Ask the stroke def for its number of brush repeats - 0 means work it out
			INT32 NumberOfRepeats = pStrokeDef->NumRepeats();
			if(NumberOfRepeats == 0 && pSubRenderContext->RepeatDist > 0)
			{
				// Work out the optimal number of repeats along the path
				NumberOfRepeats = (INT32)(floor((Length/pSubRenderContext->RepeatDist) + 0.5));
			}

			// Don't got dividing by zero now...			
			if(NumberOfRepeats <= 0)
				NumberOfRepeats = 1;
		
			// Alter the repeat distance to accomodate this number of repeats
			pSubRenderContext->RepeatDist = (INT32)(Length / (double)NumberOfRepeats);
		}

		// Generate the set of trapezoids for the dest path
		ProcessPathToTrapezoids GenerateTraps(100);
		pSubRenderContext->pOutputTraps = new TrapsList(pSubRenderContext->RepeatDist);

		BOOL Failed = (pSubRenderContext->pOutputTraps == NULL);
		if (!Failed && !GenerateTraps.Init(pPath, pSubRenderContext->pOutputTraps))
			Failed = TRUE;

		ProcessFlags PFlags(TRUE, FALSE, FALSE);	// Flags are: Flatten, !QuantiseLines, !QuantiseAll
		if (!Failed && !GenerateTraps.Process(PFlags, TrapTravel_Parametric, pSubRenderContext->JoinStyle))
			Failed = TRUE;

		if (Failed)
		{
			pRender->DrawPath(pPath, this, ShapePath);
			if (!pRender->IsSubRenderStateLocked())
				pRender->SetSubRenderState(NULL);
			delete pSubRenderContext;
			return;
		}
	}

	ERROR3IF(pSubRenderContext->pOutputTraps == NULL || pValFunc == NULL,
				"Vector stroke SubRenderContext was not properly uninitialised!");

	// --- Handle background rendering. We always store all critical information in a SubRenderContext.
	// If we have to break into rendering because of background rendering, we give the context to the RndRgn
	// to keep for next time. However, when we finish rendering everything, we need to clean up - we will
	// assume that we'll make it to the end, and chnage this variable if we get interrupted.
	BOOL DeleteSubRenderContext = TRUE;

	// Lock the sub-render context so that nobody "inside" the brush uses it
	const BOOL SRContextLocked = pRender->IsSubRenderStateLocked();
	if (!SRContextLocked)
		pRender->LockSubRenderState(TRUE);

	// --- Now "render" the brush clipart tree via our Stroker
	for ( ;
			pSubRenderContext->Index < pSubRenderContext->pOutputTraps->GetNumTraps() && DeleteSubRenderContext;
			pSubRenderContext->Index++)
	{
		// Find the trapezoid edge list for this pass
		TrapEdgeList *pEdgeList = pSubRenderContext->pOutputTraps->GetTrapEdgeList(pSubRenderContext->Index);
		if (pEdgeList->GetNumEdges() < 2)
		{
			ERROR3("No map traps when stroking! Subpath stripped\n");
			continue;
		}

		// And render away
		pRender->SaveContext();

		Node* pNode = pBrush->FindFirstForUnclippedInkRender(pRender);
		while (pNode)
		{
			// Prepare the stroker to stroke this sub-stroke
			Stroker.PrepareToStroke(pEdgeList);

			if (pNode->IsAnAttribute())
			{
				// If we are overriding the fill/transparency with the one applied to the stroke,
				// then we simply throw away all fill/transparency attributes as we render
				// (We do this on the fly rather than as we make the brush so that the user can
				// toggle this mode on and off at any time if they change their mind)
				BOOL RenderIt = TRUE;
				if ( (pStrokeDef->OverrideFill()  && ((NodeAttribute *)pNode)->IsAColourFill())	||
					 (pStrokeDef->OverrideFill()  && ((NodeAttribute *)pNode)->IsAStrokeColour()) ||
					 (pStrokeDef->OverrideTrans() && ((NodeAttribute *)pNode)->IsAStrokeTransp()) ||
					 (pStrokeDef->OverrideTrans() && ((NodeAttribute *)pNode)->IsATranspFill()) )
				{
					RenderIt = FALSE;
				}

				if (RenderIt)
				{
					// We must modify all attributes to lie in the destination stroke.
					// This includes fill/trans geometry endpoints, line widths, and
					// also possibly modifying transparency levels to allow a flat transparency
					// to be applied to the whole stroke.
					AttributeValue *pAttrValue = ((NodeAttribute *)pNode)->GetAttributeValue();
					AttributeValue *pNewValue  = pAttrValue->MouldIntoStroke(&Stroker, 1.0);
					//****!!!!TODO - Just above, we have the chance to handle transparency better
					// - we could at least scale all transparencies by passing a flat scale factor into
					// the MouldIntoStroke call.

					if (pNewValue != NULL)
						pNewValue->Render(pRender, TRUE);		// The RndRgn will delete this when it's done with
					else
						pNode->Render(pRender);					// No change, so render the original attribute
				}
			}
			else if (pNode->IsNodePath())
			{
				// Stroke the trapezoids into the output path
				pOutput->ClearPath();
				if (!Stroker.StrokePath(&((NodePath *)pNode)->InkPath, pOutput))
					break;

				pRender->SetWindingRule(NonZeroWinding);
				pRender->DrawPath(pOutput, this, ShapePath);
			}
//				else
//					TRACEUSER( "Jason", _T("\nBrush node %s not rendered\n"), pNode->GetRuntimeClass()->m_lpszClassName);

			pNode = pNode->FindNextForUnclippedInkRender(pRender);
		}

		pRender->RestoreContext();

		// --- Now check if we should break into rendering for background rendering purposes
		// If the Sub-render-context is locked, then we're inside a blend or something, and it's too dangerous
		// for us to store our sub-render state, so we have no choice but to render until we finish.
		// BLOCK
		if (!SRContextLocked && IS_A(pRender, GRenderDIB))
		{
			View *pView = pRender->GetRenderView();
			if (pView != NULL && !pRender->RenderTreeCanContinue())
			{
				// We have been interrupted by the background redraw system.
				// We will immediately exit, storing our SubRenderContext away into the
				// RenderRegion for the next time it calls us (see below).
				DeleteSubRenderContext = FALSE;

				// Drop through and let the loop condition handle exit
			}
		}
	}

	// If we locked the sub-render context, then we must restore it
	if (!SRContextLocked)
		pRender->LockSubRenderState(FALSE);

	// If we have finished rendering everything, then we vape our sub render context.
	// (We even check if we were interrupted just as we finished the final iteration)
	if (DeleteSubRenderContext || pSubRenderContext->Index >= pSubRenderContext->pOutputTraps->GetNumTraps())
	{
		if (!SRContextLocked)
			pRender->SetSubRenderState(NULL);
		delete pSubRenderContext;
		pSubRenderContext = NULL;
	}
	else
	{
		if (!SRContextLocked)
			pRender->SetSubRenderState(pSubRenderContext);
	}

	delete pOutput;
	pOutput = NULL;
#endif
}
Example #9
0
void ArrangeAlignment::RedrawDiagram(ReDrawInfoType* ExtraInfo)
{
	// objects drawn in the render region must be relatively large in the given coord space
	// else Gavin's curve flattening results in visible straight lines
	// so every dimension is scaled by scale
	INT32 scale=1000;

	// make a render region
	DocRect VirtRendRect;
	VirtRendRect.lo.x=-1*scale;
	VirtRendRect.lo.y=-2*scale;
	VirtRendRect.hi.x=(DiagWidth +1)*scale;
	VirtRendRect.hi.y=(DiagHeight+2)*scale;
	RenderRegion* pRender=CreateGRenderRegion(&VirtRendRect,ExtraInfo);

	if (pRender!=NULL)
	{
		pRender->SaveContext();

		// currently this must be set here before any colour tables calculated
		Quality             AntiAliasQuality(Quality::QualityMax);
		QualityAttribute    AntiAliasQualityAttr(AntiAliasQuality);
		pRender->SetQuality(&AntiAliasQualityAttr,FALSE);

		// Render the background rectangle
		DialogColourInfo RedrawColours;
		pRender->SetLineColour(RedrawColours.DialogBack());
		pRender->SetFillColour(RedrawColours.DialogBack());
		pRender->DrawRect(&VirtRendRect);

		// declared at this scope else RestoreContext() dies!
		RadialFillAttribute Fill;		

		// set up some defaults used by all objects
		Fill.MakeElliptical();
		Fill.Colour=DocColour(255,255,255);
		pRender->SetLineColour(BLACK);
		pRender->SetLineWidth(0);

		for (INT32 i=0; i<DiagRects; i++)
		{
			// reverse order in which objets are rendered (now filled!)
			INT32 j=DiagRects-1-i;

			// set fill colour of each object
			switch (j)
			{
				case  0: Fill.EndColour=DocColour(255,255,0); break;
				case  1: Fill.EndColour=DocColour(0,0,255);   break;
				case  2: Fill.EndColour=DocColour(255,0,0);   break;
				case  3: Fill.EndColour=DocColour(0,160,0);   break;
				default: Fill.EndColour=DocColour(0,0,0);     break;
			}

			// get bound rect of object to be drawn
			INT32 x=DiagRectX[Align.h][j].lo*scale;
			INT32 w=DiagRectX[Align.h][j].hi*scale-x;
			INT32 y=DiagRectY[Align.v][j].lo*scale;
			INT32 h=DiagRectY[Align.v][j].hi*scale-y;

			// create shape and fill geometries
			Path shape;
			shape.Initialise(16,8);
			shape.IsFilled=TRUE;
			shape.FindStartOfPath();
			switch (j)
			{
				case 0:
				{
					// create a rectangle
					shape.InsertMoveTo(DocCoord(x,y));
					shape.InsertLineTo(DocCoord(x,y+h));
					shape.InsertLineTo(DocCoord(x+w,y+h));
					shape.InsertLineTo(DocCoord(x+w,y));
					shape.InsertLineTo(DocCoord(x,y));

//					// create a radial fill
//					Fill.StartPoint=DocCoord(x+w*3/16,y+h*3/4);
//					Fill.EndPoint  =DocCoord(x+w*3/8,y+h/2);
//					Fill.EndPoint2 =DocCoord(x+w*3/8,y+h);
					break;
				}

				case 1:
				{
					// create a pseudo ellipse
					shape.InsertMoveTo( DocCoord(x,y+h/2));
					shape.InsertCurveTo(DocCoord(x,y+h*3/4),  DocCoord(x+w/4,y+h),  DocCoord(x+w/2,y+h));
					shape.InsertCurveTo(DocCoord(x+w*3/4,y+h),DocCoord(x+w,y+h*3/4),DocCoord(x+w,y+h/2));
					shape.InsertCurveTo(DocCoord(x+w,y+h/4),  DocCoord(x+w*3/4,y),  DocCoord(x+w/2,y));
					shape.InsertCurveTo(DocCoord(x+w/4,y),    DocCoord(x,y+h/4),    DocCoord(x,y+h/2));

// 					// create a radial fill
//					Fill.StartPoint=DocCoord(x+w*3/8,y+h*5/8);
//					Fill.EndPoint  =DocCoord(x+w*6/8,y+h/4);
//					Fill.EndPoint2 =DocCoord(x+w*6/8,y+h);
					break;
				}

				default:
				{
					// create a rounded rectangle
					shape.InsertMoveTo( DocCoord(x,y+h/2));
					shape.InsertCurveTo(DocCoord(x,y+h),  DocCoord(x,y+h),  DocCoord(x+w/2,y+h));
					shape.InsertCurveTo(DocCoord(x+w,y+h),DocCoord(x+w,y+h),DocCoord(x+w,y+h/2));
					shape.InsertCurveTo(DocCoord(x+w,y),  DocCoord(x+w,y),  DocCoord(x+w/2,y));
					shape.InsertCurveTo(DocCoord(x,y),    DocCoord(x,y),    DocCoord(x,y+h/2));

// 					// create a radial fill
//					Fill.StartPoint=DocCoord(x+w*3/16,y+h*3/4);
//					Fill.EndPoint  =DocCoord(x+w*3/8,y+h/2);
//					Fill.EndPoint2 =DocCoord(x+w*3/8,y+h);
					break;
				}

			}
//			pRender->SetFillGeometry(&Fill,FALSE);
			pRender->SetFillColour(Fill.EndColour);
			pRender->DrawPath(&shape);
		}

		pRender->RestoreContext();
		DestroyGRenderRegion(pRender);	// also blt's to screen
	}
}
Example #10
0
void RenderDemoDlg::RenderControl(ReDrawInfoType* ExtraInfo)
{
	// Go get a render region
	DocRect VirtualSize(-ExtraInfo->dx/2, -ExtraInfo->dy/2, ExtraInfo->dx/2, ExtraInfo->dy/2);
	RenderRegion* pRender = CreateGRenderRegion(&VirtualSize, ExtraInfo);
	if (pRender!=NULL)
	{
		DialogColourInfo RedrawColours;		// Get a supplier for default dlg colours

		// Render stuff in here
		// Build a Linear fill attribute
		LinearFillAttribute MyGradFill;
		MyGradFill.Colour = DocColour(255, 255, 0);
		MyGradFill.EndColour = DocColour(0, 255, 255);
		MyGradFill.StartPoint = DocCoord(0, ExtraInfo->dy);
		MyGradFill.EndPoint = DocCoord(ExtraInfo->dx, 0);

		// Build a path
		Path InkPath;
		InkPath.Initialise(12,12);
		InkPath.FindStartOfPath();

		// Get the coords used to build a shape
		INT32 dx = ExtraInfo->dx / 2;
		INT32 dy = ExtraInfo->dy / 2;
		INT32 Midx = ExtraInfo->dx / 4;
		INT32 Midy = ExtraInfo->dy / 4;

		// build a circle in the middle of the control
		InkPath.InsertMoveTo(DocCoord(Midx, dy));
		InkPath.InsertCurveTo(DocCoord(Midx+Midx/2, dy), DocCoord(dx, Midy+Midy/2), DocCoord(dx, Midy));
		InkPath.InsertCurveTo(DocCoord(dx, Midy-Midy/2), DocCoord(Midx+Midx/2, 0), DocCoord(Midx, 0));
		InkPath.InsertCurveTo(DocCoord(Midx-Midx/2, 0), DocCoord(0, Midy-Midy/2), DocCoord(0, Midy));
		InkPath.InsertCurveTo(DocCoord(0, Midy+Midy/2), DocCoord(Midx-Midx/2, dy), DocCoord(Midx, dy));
		InkPath.IsFilled = TRUE;
		
		// A Grey colour [...hmmm, it's not a very grey grey any more... oragnge more like]
		DocColour Grey(255,200,0);

		// Render the attributes and the a rectangle
		pRender->SaveContext();
		pRender->SetLineColour(Grey);

		// Draw a rectangle to fill in the background - Fill with Dialogue Background colour
		DocRect DrawMe(0, 0, ExtraInfo->dx, ExtraInfo->dy);
		pRender->SetFillColour(RedrawColours.DialogBack());
		pRender->DrawRect(&VirtualSize);

		// Draw some shapes and stuff
		pRender->SetFillGeometry(&MyGradFill, FALSE);
		pRender->DrawPath(&InkPath);

		// Build a path
		Path TriPath;
		TriPath.Initialise(12,12);
		TriPath.FindStartOfPath();

		// build a circle in the middle of the control
		TriPath.InsertMoveTo(VirtualSize.lo);
		TriPath.InsertLineTo(DocCoord(VirtualSize.hi.x, VirtualSize.lo.y));
		TriPath.InsertLineTo(DocCoord(0, VirtualSize.hi.y));
		TriPath.InsertLineTo(VirtualSize.lo);
		TriPath.IsFilled = TRUE;

		LinearFillAttribute MyTriFill;
		MyTriFill.Colour = ShowFirst ? First : Second;
		MyTriFill.EndColour = DocColour(0,0,0);
		MyTriFill.StartPoint = DocCoord(ExtraInfo->dx, 0);
		MyTriFill.EndPoint = DocCoord(0, ExtraInfo->dy);

		pRender->SetFillGeometry(&MyTriFill, FALSE);
		pRender->DrawPath(&TriPath);

		pRender->RestoreContext();

		// Get rid of the render region
		DestroyGRenderRegion(pRender);
	}

	// and animate it!
	if (ShowFirst)
	{
		INT32 Red, Green, Blue;
		First.GetRGBValue(&Red, &Green, &Blue);

		if (Blue>0)
		{
			// Set the colour back again
			Blue -= 10;
			First.SetRGBValue(Red, Green, Blue);

			// redraw it
			InvalidateGadget(_R(IDC_REDRAW_ME));
		}
	}
	else
	{
		// Set the colour back to how it was
		First.SetRGBValue(255, 0, 250);
	}
}
Example #11
0
/********************************************************************************************

>	BOOL BlendHelpers::BlendPaths(BlendNodeParam * pParam, Path * pPath)

	Author:		David_McClarnon (Xara Group Ltd) <*****@*****.**>
	Created:	21/2/2000
	Inputs:		The blend node parameter
	Outputs:	The blended path is stored in three arrays: the coords, the verbs, and the flags.
				The arrays are:
	
					pTempCoords
					pTempVerbs
					pTempFlags

					ArrayLength = the length of all three arrays

				This allows the caller to decide what to do with the blended path in a very flexible way.

	Returns:	TRUE if successful, FALSE otherwise
	Purpose:	Blends two BlendPath objects by the amount specified in BlendRatio
	SeeAlso:	-
********************************************************************************************/
BOOL BlendHelpers::BlendPaths(BlendNodeParam * pParam, Path * pPath)
{
	// Check entry params
	BlendPath * pBlendPathStart = pParam->GetStartBlendPath();
	BlendPath * pBlendPathEnd   = pParam->GetEndBlendPath();

	ERROR2IF(!pBlendPathStart->GetBlendNode()->IsNodePath(), FALSE,
		"Start blend path's node isn't a node path");

	ERROR2IF(!pBlendPathEnd->GetBlendNode()->IsNodePath(), FALSE,
		"End blend path's node isn't a node path");

	BOOL    ok = (pBlendPathStart != NULL && pBlendPathEnd != NULL);
 	if (ok) ok = (pBlendPathStart->GetBlendNode() != NULL && pBlendPathEnd->GetBlendNode() != NULL);
	ERROR3IF(!ok,"One or more NULL entry params");
	if (!ok) return FALSE;

	// Get the types of the two paths
	PathTypeEnum PathTypeStart = pBlendPathStart->GetPathType();
	PathTypeEnum PathTypeEnd   = pBlendPathEnd  ->GetPathType();
	
	// The blended path will be closed if either of the paths is a shape
	BOOL Closed = (PathTypeStart == PATHTYPE_SHAPE) || (PathTypeEnd == PATHTYPE_SHAPE);

	Path * pPathStart = NULL;

	// Find the paths associated with the start and end blend paths
	if (pBlendPathStart->GetBlendNode()->IsNodePath())
	{
		pPathStart = &(((NodePath *)pBlendPathStart->GetBlendNode())->InkPath);
	}

	Path * pPathEnd = NULL;

	if (pBlendPathEnd->GetBlendNode()->IsNodePath())
	{
		pPathEnd   = &(((NodePath *)pBlendPathEnd->GetBlendNode())->InkPath);
	}

	// Calculate how large the arrays have to be to store the blended path definition
	INT32 DestPathSize = ((pPathStart->GetNumCoords()+pPathEnd->GetNumCoords())*3)+500;

	// Get some arrays used to hold the blended path data, and error if any are NULL
	DocCoord*  	pDestCoords = GetCoordArray(DestPathSize);
	PathVerb*  	pDestVerbs  = GetVerbArray(DestPathSize);
	PathFlags* 	pDestFlags  = GetFlagArray(DestPathSize);
	UINT32* 		pBuff 		= GetGBlendBuff(DestPathSize);
	if (pDestCoords == NULL || pDestVerbs == NULL || pDestFlags == NULL || pBuff == NULL)
		return FALSE;

	// This section copes with the case when blending a line with a shape.
	// In this case we need to get a temp path the is actually a shape version of the line.
	// The line is simply reversed back onto itself to form a shape that would look identical to the 
	// line if rendered.  This allows the line to appear to open up to the shape when blended.
	Path Shape;
	if (PathTypeStart != PathTypeEnd)
	{
		BOOL ok = FALSE;
		if (!Shape.Initialise()) return FALSE;

		// if going from a line to a shape, convert the start path to a shape
		if (PathTypeStart == PATHTYPE_LINE && PathTypeEnd == PATHTYPE_SHAPE)
		{
			ok = NodeBlender::ConvertLineToShape(pPathStart,&Shape);
			pPathStart = &Shape;
		}

		// if going from a shape to a line, convert the end path to a shape
		if (PathTypeStart == PATHTYPE_SHAPE && PathTypeEnd == PATHTYPE_LINE)
		{
			ok = NodeBlender::ConvertLineToShape(pPathEnd,&Shape);
			pPathEnd = &Shape;
		}

		if (!ok) return FALSE;
	}

	// The blend should do a one-to-one mapping when the OneToOne flag is set AND both paths
	// have the same number of elements
	BOOL OneToOne = FALSE;
	if (pParam->GetOneToOne())
		OneToOne = (pBlendPathStart->GetNumElements() == pBlendPathEnd->GetNumElements());

	// Now actually blend the two paths

	GBlend GBlendObj;

	// Define the blend
	GBlendObj.Define(	(PPOINT)pPathStart->GetCoordArray(),	// Specify the start path
						pPathStart->GetVerbArray(),
						pPathStart->GetNumCoords(),

						(PPOINT)pPathEnd  ->GetCoordArray(),	// Specify the end path
						pPathEnd  ->GetVerbArray(),
						pPathEnd  ->GetNumCoords(),

						OneToOne,								// The one-to-one flag
						1024,								// Flatness

						pBuff,									// Buffer for GBlend to use
						DestPathSize*sizeof(UINT32));			// The buffer size

	// Blend the paths
	m_ArrayLength = GBlendObj.Blend(pParam->GetBlendRatio(),	// The blend ratio, 0.0 < BlendRatio < 1.0
									(PPOINT)pDestCoords,		// Array to store blended coords
									pDestVerbs,					// Array to store blended verbs
									DestPathSize);				// The num elements in the two arrays


	// If we're blending a line to another line, we need to make sure that the blended line
	// is going in a direction that corresponds to the source lines.  This ensures attributes
	// that depend on this direction (e.g. start and end arrows) look correct.
	//
	// When creating blend paths of lines, we can detect if the blend path has been reversed,
	// in relation to the original path, by the original mapping value.
	// If it's 0 it has NOT been reversed, otherwise it's been reversed.
	//
	// If the blend ratio is <=0.5, the blended path is closest to the start blend path,
	// so we look at the start blend path's original mapping.
	//
	// If blend ration > 0.5, look at the end blend path's original mapping.
	//
	// The (BlendRation <= 0.5) cut-off point is the same as the cut-off point used in the blending
	// of attributes.
	if (pBlendPathStart->IsLine() && pBlendPathEnd->IsLine())
	{
		BlendPath* pBlendPath;
		if (pParam->GetBlendRatio() <= 0.5) 
			pBlendPath = pBlendPathStart;
		else
			pBlendPath = pBlendPathEnd;

		if (pBlendPath->GetOrigMapping() != 0)
			NodeBlender::ReversePath(pDestCoords,pDestVerbs,m_ArrayLength);
	}

	// We need to do some work on the blended path
	if (!NodeBlender::ProcessBlendedPath(pDestCoords,pDestVerbs,pDestFlags,m_ArrayLength,Closed))
		return FALSE;

	Path RetnPath;
	RetnPath.Initialise(m_ArrayLength);

	BOOL Filled  = pPathStart->IsFilled  || pPathEnd->IsFilled;
	BOOL Stroked = pPathStart->IsStroked || pPathEnd->IsStroked;

	RetnPath.MergeTwoPaths(pDestCoords,pDestVerbs,pDestFlags,m_ArrayLength,Filled);

	pPath->ClearPath();
	pPath->CloneFrom(RetnPath);
	pPath->IsFilled = Filled;
	pPath->IsStroked = Stroked;
	
	return TRUE;
}