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; }
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); }
/******************************************************************************************** > 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; }