char * AP_Dialog_MarkRevisions::getComment1()
{
	_initRevision();

	if(!m_pRev || m_bForceNew)
		return NULL;

	bool bFree = false;

	const UT_UCS4Char * pC = m_pRev->getDescription();

	if(!pC)
		return NULL;

	// now we run this string through fribidi
	if(XAP_App::getApp()->theOSHasBidiSupport() == XAP_App::BIDI_SUPPORT_NONE)
	{
		UT_UCS4Char *pStr2 = 0;
		UT_uint32 iLen = UT_UCS4_strlen(pC);

		pStr2  = (UT_UCS4Char *)UT_calloc( iLen + 1, sizeof(UT_UCS4Char));
		UT_return_val_if_fail(pStr2,NULL);
		bFree = true;

		UT_BidiCharType iDomDir = UT_bidiGetCharType(pC[0]);

		UT_bidiReorderString(pC, iLen, iDomDir, pStr2);
		pC = pStr2;

	}

	char * pComment = (char *)UT_calloc(UT_UCS4_strlen(pC) + 1, sizeof(char));
	UT_return_val_if_fail(pComment,NULL);

	UT_UCS4_strcpy_to_char(pComment,pC);

	if(bFree)
	{
		FREEP(pC);
	}

	return pComment;
}
bool GR_Graphics::itemize(UT_TextIterator & text, GR_Itemization & I)
{
	UT_return_val_if_fail(text.getStatus() == UTIter_OK, false);
	
	I.clear();
	UT_uint32 iCurOffset = 0, iLastOffset = 0;
	UT_uint32 iPosStart = text.getPosition();

	// the main loop that will span the whole text of the iterator
	while(text.getStatus() == UTIter_OK)
	{
		UT_BidiCharType iPrevType, iLastStrongType = UT_BIDI_UNSET, iType;
		
		UT_UCS4Char c = text.getChar();
		
		UT_return_val_if_fail(text.getStatus() == UTIter_OK, false);

		iType = UT_bidiGetCharType(c);
#if 0
		// this branch of code breaks at all direction bounaries
		// it is disabled because doing that causes bug 8099
		iCurOffset = iLastOffset = text.getPosition();
		++text;
		
		// this loop will cover a single homogenous item
		while(text.getStatus() == UTIter_OK)
		{
			iPrevType = iType;

			c = text.getChar();
			UT_return_val_if_fail(text.getStatus() == UTIter_OK, false);

			// remember the offset
			iLastOffset = text.getPosition();
			
			iType = UT_bidiGetCharType(c);
			if(iType != iPrevType)
			{
				break;
			}

			++text;
		}
#else
		//we have to break the text into chunks that each will go into a
		//separate run in a manner that will ensure that the text will
		//be correctly processed later. The most obvious way is to
		//break every time we encounter a change of directional
		//properties. Unfortunately that means breaking at each white
		//space, which adds a huge amount of processing due to
		//allocating and deleting runs when loading a
		//document. The following code tries to catch out the obvious
		//cases when the span can remain intact. Tomas, Jan 28, 2003

		// remember where we are ...
		iCurOffset = iLastOffset = text.getPosition();
		++text;

		UT_BidiCharType iNextType;
		
		// this loop will cover a single homogenous item
		while(text.getStatus() == UTIter_OK)
		{
			iPrevType = iType;
			if(UT_BIDI_IS_STRONG(iType))
				iLastStrongType = iType;
			
			c = text.getChar();
			UT_return_val_if_fail(text.getStatus() == UTIter_OK, false);

			// remember the offset
			iLastOffset = text.getPosition();
			++text;
			
			iType = UT_bidiGetCharType(c);
			if(iType != iPrevType)
			{
				// potential direction boundary see if we can ignore
				// it
				bool bIgnore = false;
#if 0
				// this assumption is not true; for instance in the
				// sequence ") " the parenthesis and the space can
				// resolve to different directions
				// 
				// I am leaving it here so that I do not add it one
				// day again (Tomas, Apr 10, 2003)
				
				if(UT_BIDI_IS_NEUTRAL(iPrevType) && UT_BIDI_IS_NEUTRAL(iType))
				{
					// two neutral characters in a row will have the same
					// direction
					xxx_UT_DEBUGMSG(("GR_Graphics::itemize: ntrl->ntrl (c=0x%04x)\n",c));
					bIgnore = true;
				}
				else
#endif
				if(UT_BIDI_IS_STRONG(iPrevType) && UT_BIDI_IS_NEUTRAL(iType))
				{
					// we can ignore a neutral character following a
					// strong one if it is followed by a strong
					// character of identical type to the previous one
					xxx_UT_DEBUGMSG(("GR_Graphics::itemize: strong->ntrl (c=0x%04x)\n",c));
					
					// take a peek at what follows
					UT_uint32 iOldPos = text.getPosition();
					
					while(text.getStatus() == UTIter_OK)
					{
						UT_UCS4Char c2 = text.getChar();
						UT_return_val_if_fail(text.getStatus() == UTIter_OK, false);

						++text;
						
						iNextType = UT_bidiGetCharType(c2);
						xxx_UT_DEBUGMSG(("GR_Graphics::itemize: iNextType 0x%04x\n", iNextType));
						
						if(iNextType == iPrevType)
						{
							bIgnore = true;
							break;
						}

						// if the next character is strong, we cannot
						// ignore the boundary
						if(UT_BIDI_IS_STRONG(iNextType))
							break;
					}

					// restore position
					text.setPosition(iOldPos);
				}
				else if(UT_BIDI_IS_NEUTRAL(iPrevType) && UT_BIDI_IS_STRONG(iType))
				{
					// a neutral character followed by a strong one -- we
					// can ignore it, if the neutral character was
					// preceeded by a strong character of the same
					// type
					if(iType == iLastStrongType)
					{
						bIgnore = true;
					}
					xxx_UT_DEBUGMSG(("GR_Graphics::itemize: ntrl->strong (c=0x%04x)\n",c));
				}
				else
				{
					// in all other cases we will split
					xxx_UT_DEBUGMSG(("GR_Graphics::itemize: other (c=0x%04x)\n",pSpan[i]));
				}

				xxx_UT_DEBUGMSG(("GR_Graphics::itemize: bIgnore %d\n",static_cast<UT_uint32>(bIgnore)));
				if(!bIgnore)
					break;
			}
			
		}
#endif
		
		I.addItem(iCurOffset - iPosStart, new GR_XPItem(GRScriptType_Undefined));
	}

	// add an extra record of type Void to allow for calculation of
	// length of the last item
	// iLastOffset is the offset of the last valid character; the Void
	// offset is one beyond that
	I.addItem(iLastOffset - iPosStart + 1, new GR_XPItem(GRScriptType_Void));
	return true;
}
/*!
  Insert a span of text into the document
 \param b Buffer containing UCS text to insert

 Uses appropriate function for clipboard or file
 */
bool IE_Imp_Text::_insertSpan(UT_GrowBuf &b)
{
	UT_uint32 iLength = b.getLength();
	const UT_UCS4Char * pData = (const UT_UCS4Char *)b.getPointer(0);

	// handle block direction if needed ...
	if(pData && m_bBlockDirectionPending)
	{
		const UT_UCS4Char * p = pData;

		// we look for the first strong character
		for(UT_uint32 i = 0; i < iLength; i++, p++)
		{
			UT_BidiCharType type = UT_bidiGetCharType(*p);

			if(UT_BIDI_IS_STRONG(type))
			{
				m_bBlockDirectionPending = false;

				// set 'dom-dir' property of the block ...
				const gchar * propsArray[3];
				propsArray[0] = "props";
				propsArray[1] = NULL;
				propsArray[2] = NULL;

				UT_String props("dom-dir:");
				
				if(UT_BIDI_IS_RTL(type))
					props += "rtl;text-align:right";
				else
					props += "ltr;text-align:left";

				propsArray[1] = props.c_str();
				
				// we need to modify the existing formatting ...
				if(m_pBlock == NULL)
				{
					PL_StruxDocHandle sdh = NULL;
					if(getDoc()->getStruxOfTypeFromPosition(getDocPos(), PTX_Block,&sdh))
					{
						m_pBlock = static_cast<pf_Frag_Strux *>(const_cast<void *>(sdh));
					}
				}
				appendStruxFmt(m_pBlock, static_cast<const gchar **>(&propsArray[0]));
			
				// if this is the first data in the block and the first
				// character is LRM or RLM followed by a strong character,
				// then we will remove it
				if(m_bFirstBlockData && i==0 && iLength > 1 && (*p == UCS_LRM || *p == UCS_RLM))
				{
					UT_BidiCharType next_type = UT_bidiGetCharType(*(p+1));
					if(UT_BIDI_IS_STRONG(next_type))
					{
						pData++;
						iLength--;
					}
				}
				
				break;
			}
		}
	}
	
	bool bRes = appendSpan (pData, iLength);
	b.truncate(0);
	m_bFirstBlockData = false;
	return bRes;
}
bool Text_Listener::populate(PL_StruxFmtHandle /*sfh*/,
								  const PX_ChangeRecord * pcr)
{
	switch (pcr->getType())
	{
	case PX_ChangeRecord::PXT_InsertSpan:
		{
			const PX_ChangeRecord_Span * pcrs = static_cast<const PX_ChangeRecord_Span *>(pcr);

			PT_AttrPropIndex api = pcr->getIndexAP();
			_handleDirMarker(api);

			PT_BufIndex bi = pcrs->getBufIndex();
			const UT_UCS4Char * pData = m_pDocument->getPointer(bi);

			// first see if there is a pending marker (for block direction)
			// and handle it
			if(pData && m_eDirMarkerPending != DO_UNSET)
			{
				UT_UCS4Char cRLM = UCS_RLM;
				UT_UCS4Char cLRM = UCS_LRM;

				UT_BidiCharType type = UT_bidiGetCharType(*pData);
				
				if(m_eDirMarkerPending == DO_RTL && type == UT_BIDI_RTL)
				{
					//the override corresponds to the marker, no marker needed
					m_eDirMarkerPending = DO_UNSET;
				}
				else if(m_eDirMarkerPending == DO_RTL && type == UT_BIDI_LTR)
				{
					//need to issue marker
					_outputData(&cRLM, 1);
					m_eDirMarkerPending = DO_UNSET;
				}
				else if(m_eDirMarkerPending == DO_LTR && type == UT_BIDI_LTR)
				{
					//the override corresponds to the marker, no marker needed
					m_eDirMarkerPending = DO_UNSET;
				}
				else if(m_eDirMarkerPending == DO_LTR && type == UT_BIDI_RTL)
				{
					//need to issue marker
					_outputData(&cLRM, 1);
					m_eDirMarkerPending = DO_UNSET;
				}
			}
			
			_outputData(pData,pcrs->getLength());

			return true;
		}

	case PX_ChangeRecord::PXT_InsertObject:
		{
			// TODO decide how to indicate objects in text output.

			const PX_ChangeRecord_Object * pcro = static_cast<const PX_ChangeRecord_Object *>(pcr);
			//PT_AttrPropIndex api = pcr->getIndexAP();
			fd_Field* field;
			switch (pcro->getObjectType())
			{
			case PTO_Image:
				return true;

			case PTO_Field:
				// Lossy, but pretty much unavoidable
				field = pcro->getField();
				UT_return_val_if_fail(field, false);

				m_pie->populateFields ();
				if(field->getValue() != NULL)
					m_pie->write(field->getValue());

				return true;
			
			case PTO_Bookmark:
				return true;
			
			case PTO_Hyperlink:
				return true;

			case PTO_Embed:
				return true;

			case PTO_Math:
				return true;

			case PTO_Annotation:
				return true;
                
			case PTO_RDFAnchor:
				return true;

			default:
				UT_ASSERT_HARMLESS(UT_TODO);
				return true;
			}
		}

	case PX_ChangeRecord::PXT_InsertFmtMark:
		return true;

	default:
		UT_ASSERT_HARMLESS(0);
		return false;
	}
}