Exemplo n.º 1
0
void CPDF_TextPage::ProcessTextObject(PDFTEXT_Obj Obj) {
  CPDF_TextObject* pTextObj = Obj.m_pTextObj.Get();
  if (fabs(pTextObj->GetRect().Width()) < kSizeEpsilon)
    return;
  CFX_Matrix formMatrix = Obj.m_formMatrix;
  CPDF_Font* pFont = pTextObj->GetFont();
  CFX_Matrix matrix = pTextObj->GetTextMatrix() * formMatrix;

  FPDFText_MarkedContent ePreMKC = PreMarkedContent(Obj);
  if (ePreMKC == FPDFText_MarkedContent::Done) {
    m_pPreTextObj = pTextObj;
    m_perMatrix = formMatrix;
    return;
  }
  GenerateCharacter result = GenerateCharacter::None;
  if (m_pPreTextObj) {
    result = ProcessInsertObject(pTextObj, formMatrix);
    if (result == GenerateCharacter::LineBreak)
      m_CurlineRect = Obj.m_pTextObj->GetRect();
    else
      m_CurlineRect.Union(Obj.m_pTextObj->GetRect());

    switch (result) {
      case GenerateCharacter::None:
        break;
      case GenerateCharacter::Space: {
        Optional<PAGECHAR_INFO> pGenerateChar =
            GenerateCharInfo(TEXT_SPACE_CHAR);
        if (pGenerateChar) {
          if (!formMatrix.IsIdentity())
            pGenerateChar->m_Matrix = formMatrix;
          m_TempTextBuf.AppendChar(TEXT_SPACE_CHAR);
          m_TempCharList.push_back(*pGenerateChar);
        }
        break;
      }
      case GenerateCharacter::LineBreak:
        CloseTempLine();
        if (m_TextBuf.GetSize()) {
          AppendGeneratedCharacter(TEXT_RETURN_CHAR, formMatrix);
          AppendGeneratedCharacter(TEXT_LINEFEED_CHAR, formMatrix);
        }
        break;
      case GenerateCharacter::Hyphen:
        if (pTextObj->CountChars() == 1) {
          CPDF_TextObjectItem item;
          pTextObj->GetCharInfo(0, &item);
          WideString wstrItem =
              pTextObj->GetFont()->UnicodeFromCharCode(item.m_CharCode);
          if (wstrItem.IsEmpty())
            wstrItem += (wchar_t)item.m_CharCode;
          wchar_t curChar = wstrItem[0];
          if (IsHyphenCode(curChar))
            return;
        }
        while (m_TempTextBuf.GetSize() > 0 &&
               m_TempTextBuf.AsStringView()[m_TempTextBuf.GetLength() - 1] ==
                   0x20) {
          m_TempTextBuf.Delete(m_TempTextBuf.GetLength() - 1, 1);
          m_TempCharList.pop_back();
        }
        PAGECHAR_INFO* charinfo = &m_TempCharList.back();
        m_TempTextBuf.Delete(m_TempTextBuf.GetLength() - 1, 1);
        charinfo->m_Unicode = 0x2;
        charinfo->m_Flag = FPDFTEXT_CHAR_HYPHEN;
        m_TempTextBuf.AppendChar(0xfffe);
        break;
    }
  } else {
    m_CurlineRect = Obj.m_pTextObj->GetRect();
  }

  if (ePreMKC == FPDFText_MarkedContent::Delay) {
    ProcessMarkedContent(Obj);
    m_pPreTextObj = pTextObj;
    m_perMatrix = formMatrix;
    return;
  }
  m_pPreTextObj = pTextObj;
  m_perMatrix = formMatrix;
  float baseSpace = CalculateBaseSpace(pTextObj, matrix);

  const bool bR2L = IsRightToLeft(*pTextObj, *pFont);
  const bool bIsBidiAndMirrorInverse =
      bR2L && (matrix.a * matrix.d - matrix.b * matrix.c) < 0;
  int32_t iBufStartAppend = m_TempTextBuf.GetLength();
  int32_t iCharListStartAppend =
      pdfium::CollectionSize<int32_t>(m_TempCharList);

  float spacing = 0;
  const size_t nItems = pTextObj->CountItems();
  for (size_t i = 0; i < nItems; ++i) {
    CPDF_TextObjectItem item;
    PAGECHAR_INFO charinfo;
    pTextObj->GetItemInfo(i, &item);
    if (item.m_CharCode == static_cast<uint32_t>(-1)) {
      WideString str = m_TempTextBuf.MakeString();
      if (str.IsEmpty())
        str = m_TextBuf.AsStringView();
      if (str.IsEmpty() || str[str.GetLength() - 1] == TEXT_SPACE_CHAR)
        continue;

      float fontsize_h = pTextObj->m_TextState.GetFontSizeH();
      spacing = -fontsize_h * item.m_Origin.x / 1000;
      continue;
    }
    float charSpace = pTextObj->m_TextState.GetCharSpace();
    if (charSpace > 0.001)
      spacing += matrix.TransformDistance(charSpace);
    else if (charSpace < -0.001)
      spacing -= matrix.TransformDistance(fabs(charSpace));
    spacing -= baseSpace;
    if (spacing && i > 0) {
      float fontsize_h = pTextObj->m_TextState.GetFontSizeH();
      uint32_t space_charcode = pFont->CharCodeFromUnicode(' ');
      float threshold = 0;
      if (space_charcode != CPDF_Font::kInvalidCharCode)
        threshold = fontsize_h * pFont->GetCharWidthF(space_charcode) / 1000;
      if (threshold > fontsize_h / 3)
        threshold = 0;
      else
        threshold /= 2;
      if (threshold == 0) {
        threshold = static_cast<float>(GetCharWidth(item.m_CharCode, pFont));
        threshold = NormalizeThreshold(threshold, 300, 500, 700);
        threshold = fontsize_h * threshold / 1000;
      }
      if (threshold && (spacing && spacing >= threshold)) {
        charinfo.m_Unicode = TEXT_SPACE_CHAR;
        charinfo.m_Flag = FPDFTEXT_CHAR_GENERATED;
        charinfo.m_pTextObj = pTextObj;
        charinfo.m_Index = m_TextBuf.GetLength();
        m_TempTextBuf.AppendChar(TEXT_SPACE_CHAR);
        charinfo.m_CharCode = CPDF_Font::kInvalidCharCode;
        charinfo.m_Matrix = formMatrix;
        charinfo.m_Origin = matrix.Transform(item.m_Origin);
        charinfo.m_CharBox =
            CFX_FloatRect(charinfo.m_Origin.x, charinfo.m_Origin.y,
                          charinfo.m_Origin.x, charinfo.m_Origin.y);
        m_TempCharList.push_back(charinfo);
      }
      if (item.m_CharCode == CPDF_Font::kInvalidCharCode)
        continue;
    }
    spacing = 0;
    WideString wstrItem = pFont->UnicodeFromCharCode(item.m_CharCode);
    bool bNoUnicode = false;
    if (wstrItem.IsEmpty() && item.m_CharCode) {
      wstrItem += static_cast<wchar_t>(item.m_CharCode);
      bNoUnicode = true;
    }
    charinfo.m_Index = -1;
    charinfo.m_CharCode = item.m_CharCode;
    charinfo.m_Flag =
        bNoUnicode ? FPDFTEXT_CHAR_UNUNICODE : FPDFTEXT_CHAR_NORMAL;
    charinfo.m_pTextObj = pTextObj;
    charinfo.m_Origin = matrix.Transform(item.m_Origin);

    const FX_RECT rect =
        charinfo.m_pTextObj->GetFont()->GetCharBBox(charinfo.m_CharCode);
    const float fFontSize = pTextObj->GetFontSize() / 1000;
    charinfo.m_CharBox.top = rect.top * fFontSize + item.m_Origin.y;
    charinfo.m_CharBox.left = rect.left * fFontSize + item.m_Origin.x;
    charinfo.m_CharBox.right = rect.right * fFontSize + item.m_Origin.x;
    charinfo.m_CharBox.bottom = rect.bottom * fFontSize + item.m_Origin.y;
    if (fabsf(charinfo.m_CharBox.top - charinfo.m_CharBox.bottom) <
        kSizeEpsilon) {
      charinfo.m_CharBox.top =
          charinfo.m_CharBox.bottom + pTextObj->GetFontSize();
    }
    if (fabsf(charinfo.m_CharBox.right - charinfo.m_CharBox.left) <
        kSizeEpsilon) {
      charinfo.m_CharBox.right =
          charinfo.m_CharBox.left + pTextObj->GetCharWidth(charinfo.m_CharCode);
    }
    charinfo.m_CharBox = matrix.TransformRect(charinfo.m_CharBox);
    charinfo.m_Matrix = matrix;
    if (wstrItem.IsEmpty()) {
      charinfo.m_Unicode = 0;
      m_TempCharList.push_back(charinfo);
      m_TempTextBuf.AppendChar(0xfffe);
      continue;
    }
    int nTotal = wstrItem.GetLength();
    bool bDel = false;
    const int count = std::min(pdfium::CollectionSize<int>(m_TempCharList), 7);
    float threshold = charinfo.m_Matrix.TransformXDistance(
        static_cast<float>(TEXT_CHARRATIO_GAPDELTA) * pTextObj->GetFontSize());
    for (int n = pdfium::CollectionSize<int>(m_TempCharList);
         n > pdfium::CollectionSize<int>(m_TempCharList) - count; --n) {
      const PAGECHAR_INFO& charinfo1 = m_TempCharList[n - 1];
      CFX_PointF diff = charinfo1.m_Origin - charinfo.m_Origin;
      if (charinfo1.m_CharCode == charinfo.m_CharCode &&
          charinfo1.m_pTextObj->GetFont() == charinfo.m_pTextObj->GetFont() &&
          fabs(diff.x) < threshold && fabs(diff.y) < threshold) {
        bDel = true;
        break;
      }
    }
    if (!bDel) {
      for (int nIndex = 0; nIndex < nTotal; ++nIndex) {
        charinfo.m_Unicode = wstrItem[nIndex];
        if (charinfo.m_Unicode) {
          charinfo.m_Index = m_TextBuf.GetLength();
          m_TempTextBuf.AppendChar(charinfo.m_Unicode);
        } else {
          m_TempTextBuf.AppendChar(0xfffe);
        }
        m_TempCharList.push_back(charinfo);
      }
    } else if (i == 0) {
      WideString str = m_TempTextBuf.MakeString();
      if (!str.IsEmpty() && str[str.GetLength() - 1] == TEXT_SPACE_CHAR) {
        m_TempTextBuf.Delete(m_TempTextBuf.GetLength() - 1, 1);
        m_TempCharList.pop_back();
      }
    }
  }
  if (bIsBidiAndMirrorInverse)
    SwapTempTextBuf(iCharListStartAppend, iBufStartAppend);
}
Exemplo n.º 2
0
//+---------------------------------------------------------------------------
//
//  Member:     CDispScrollerPlus::GetNodeTransform
//              
//  Synopsis:   Return a context that can be used to transform values
//              in the source coordinate system, producing values for the
//              destination coordinate system.
//              
//  Arguments:  pContext        returns context
//              source          source coordinate system
//              destination     destination coordinate system
//              
//  Notes:      
//              
//----------------------------------------------------------------------------
void CDispScrollerPlus::GetNodeTransform(CDispContext* pContext, COORDINATE_SYSTEM source, COORDINATE_SYSTEM destination) const
{
    Assert(destination < source);
    BOOL fRightToLeft = IsRightToLeft();
    
    CSize& offset = pContext->_offset;
    CRect& rcClip = pContext->_rcClip;
    
    switch(source)
    {
    case COORDSYS_NONFLOWCONTENT:
    case COORDSYS_CONTENT:
        // COORDSYS_CONTENT --> COORDSYS_CONTAINER
        {
            CDispInfo di((CDispExtras*) _extra);
            const CSize& topLeftBorder = di._prcBorderWidths->TopLeft().AsSize();

            if(!fRightToLeft)
            {
                offset = topLeftBorder + _sizeScrollOffset;
            
                // add inset for flow child
                if(source == COORDSYS_CONTENT)
                {
                    offset += *di._pInsetOffset;
                }
            }
            else
            {
                offset.cx = _rcContainer.Width() - di._prcBorderWidths->right + _sizeScrollOffset.cx;
                offset.cy = di._prcBorderWidths->top + _sizeScrollOffset.cy;

            }
            
            // all layers clip inside border regardless of layer type
            CSize sizeContained =
                _rcContainer.Size() - topLeftBorder -
                di._prcBorderWidths->BottomRight().AsSize();
            // clip to scroll bars
            if(_fHasVScrollbar)
            {
                sizeContained.cx -= _sizeScrollbars.cx;
            }
            if(_fHasHScrollbar)
            {
                sizeContained.cy -= _sizeScrollbars.cy;
            }
            

            if(!fRightToLeft)
            {
                rcClip.SetRect(-_sizeScrollOffset.AsPoint(), sizeContained);
            }
            else
            {
                CPoint pt(_sizeScrollOffset.cx, -_sizeScrollOffset.cy);
                rcClip.SetRect(pt, sizeContained);
                rcClip.MirrorX();
            }
        }
        if(destination == COORDSYS_CONTAINER)
		{
			break;
		}
        // fall thru to continue transformation
        
    case COORDSYS_CONTAINER:
        // COORDSYS_CONTAINER --> COORDSYS_PARENT
        if(source == COORDSYS_CONTAINER)
        {
            if(HasUserClip())
            {
                rcClip = GetUserClip((CDispExtras*)_extra);
            }
            else
			{
				pContext->SetNoClip();
			}
            offset = _rcContainer.TopLeft().AsSize();
        }
        else
        {
            if(HasUserClip())
            {
                CRect rcUserClip(GetUserClip((CDispExtras*)_extra));
                rcUserClip.OffsetRect(-offset); // to source coords.
                rcClip.IntersectRect(rcUserClip);
            }
            offset += _rcContainer.TopLeft().AsSize();
        }
        if(destination == COORDSYS_PARENT)
		{
			break;
		}
        // fall thru to continue transformation
        
    default:
        Assert(source != COORDSYS_GLOBAL);
        // COORDSYS_PARENT --> COORDSYS_GLOBAL
        if(source == COORDSYS_PARENT)
        {
            if(_pParentNode != NULL)
            {
                _pParentNode->GetNodeTransform(
                    pContext,
                    GetContentCoordinateSystem(),
                    COORDSYS_GLOBAL);
            }
            else
			{
				pContext->SetToIdentity();
			}
        }
        else
        {
            if(_pParentNode != NULL)
            {
                CDispContext globalContext;
                _pParentNode->GetNodeTransform(
                    &globalContext,
                    GetContentCoordinateSystem(),
                    COORDSYS_GLOBAL);
                globalContext._rcClip.OffsetRect(-offset); // to source coords.
                rcClip.IntersectRect(globalContext._rcClip);
                offset += globalContext._offset;
            }
        }
        break;
    }
}
Exemplo n.º 3
0
//+---------------------------------------------------------------------------
//
//  Member:     CDispScrollerPlus::CalcDispInfo
//              
//  Synopsis:   Calculate clipping and positioning info for this node.
//              
//  Arguments:  rcClip          current clip rect
//              pdi             display info structure
//              
//  Notes:      
//              
//----------------------------------------------------------------------------
void CDispScrollerPlus::CalcDispInfo(const CRect& rcClip, CDispInfo* pdi) const
{
    // user clip = current clip INTERSECT optional user clip INTERSECT
    //   container bounds, in content coordinates with scrolling
    //   
    // border clip = current clip INTERSECT optional user clip INTERSECT
    //   container bounds, in container coordinates (no scrolling)
    //   
    // flow clip = current clip INTERSECT optional user clip INTERSECT
    //   container bounds, in content coordinates with scrolling
    CDispInfo& di = *pdi; // notational convenience
    
    // set scrolling offset
    di._scrollOffset = _sizeScrollOffset;
    
    // content size
    di._sizeContent = _sizeContent;
    
    // offset to local coordinates
    _rcContainer.GetTopLeft(&(di._borderOffset.AsPoint()));
    
    // calc container clip intersect with container bounds
    di._rcContainerClip = rcClip;
    di._rcContainerClip.IntersectRect(_rcContainer);
    di._rcContainerClip.OffsetRect(-di._borderOffset);
    
    // calc rect inside border and scroll bars
    di._sizeBackground =
        _rcContainer.Size() - di._prcBorderWidths->TopLeft().AsSize()
        - di._prcBorderWidths->BottomRight().AsSize();
    if(_fHasVScrollbar)
    {
        di._sizeBackground.cx -= _sizeScrollbars.cx;
    }
    if(_fHasHScrollbar)
    {
        di._sizeBackground.cy -= _sizeScrollbars.cy;
    }
    di._rcPositionedClip.SetRect(
        di._prcBorderWidths->TopLeft(), di._sizeBackground);
    di._contentOffset = di._prcBorderWidths->TopLeft().AsSize();
    di._rcPositionedClip.IntersectRect(di._rcContainerClip);
    di._rcPositionedClip.OffsetRect(-di._contentOffset);

    // contents scroll
    if(!IsSet(CDispFlags::s_fixedBackground))
    {
        di._rcPositionedClip.OffsetRect(-_sizeScrollOffset);
        di._rcBackgroundClip = di._rcPositionedClip;
    }
    else
    {
        di._rcBackgroundClip = di._rcPositionedClip;
        di._rcPositionedClip.OffsetRect(-_sizeScrollOffset);
    }
    
    // adjust for right to left coordinate system
    if(!IsRightToLeft())
    {
        di._rcFlowClip.left = max(di._rcPositionedClip.left, di._pInsetOffset->cx);
        di._rcFlowClip.right = di._rcPositionedClip.right;
    }
    else
    {
        di._contentOffset.cx = di._sizeBackground.cx + di._prcBorderWidths->left;
        if(_fHasVScrollbar)
        {
            di._contentOffset.cx += _sizeScrollbars.cx;
        }
        di._rcPositionedClip.OffsetX(-di._sizeBackground.cx);
        di._rcBackgroundClip.OffsetX(-di._sizeBackground.cx);
        
        di._rcFlowClip.left = di._rcPositionedClip.left;
        di._rcFlowClip.right = min(di._rcPositionedClip.right, di._pInsetOffset->cx);
    }

    di._rcFlowClip.top = max(di._rcPositionedClip.top, di._pInsetOffset->cy);
    di._rcFlowClip.bottom = di._rcPositionedClip.bottom;
    di._rcFlowClip.OffsetRect(-*di._pInsetOffset);
    
    // size of background is big enough to fill background and content
    di._sizeBackground.Max(di._sizeContent);
}
Exemplo n.º 4
0
//+---------------------------------------------------------------------------
//
//  Member:     CDispScrollerPlus::GetNodeTransform
//              
//  Synopsis:   Return an offset that can be added to points in the source
//              coordinate system, producing values for the destination
//              coordinate system.
//              
//  Arguments:  pOffset         returns offset value
//              source          source coordinate system
//              destination     destination coordinate system
//              
//  Notes:      
//              
//----------------------------------------------------------------------------
void CDispScrollerPlus::GetNodeTransform(CSize* pOffset, COORDINATE_SYSTEM source, COORDINATE_SYSTEM destination) const
{
    Assert(destination < source);
    BOOL fRightToLeft = IsRightToLeft();
    
    *pOffset = _afxGlobalData._Zero.size;
    
    switch(source)
    {
    case COORDSYS_NONFLOWCONTENT:
    case COORDSYS_CONTENT:
        // COORDSYS_CONTENT --> COORDSYS_CONTAINER
        {
            CDispInfo di((CDispExtras*)_extra);
            if(!fRightToLeft)
            {
                *pOffset = di._prcBorderWidths->TopLeft().AsSize() + _sizeScrollOffset;
            
                // add inset for flow child
                if(source == COORDSYS_CONTENT)
                {
                    *pOffset += *di._pInsetOffset;
                }
            }
            else
            {
                pOffset->cx = _rcContainer.Width() - di._prcBorderWidths->right + _sizeScrollOffset.cx;
                pOffset->cy = di._prcBorderWidths->top + _sizeScrollOffset.cy;

                // add inset for flow child
                if(source == COORDSYS_CONTENT)
                {
                    pOffset->cx -= di._pInsetOffset->cx;
                    pOffset->cy += di._pInsetOffset->cy;
                }
            }
        }
        if(destination == COORDSYS_CONTAINER)
		{
			break;
		}
        // fall thru to continue transformation
        
    case COORDSYS_CONTAINER:
        // COORDSYS_CONTAINER --> COORDSYS_PARENT
        *pOffset += _rcContainer.TopLeft().AsSize();
        if(destination == COORDSYS_PARENT)
		{
			break;
		}
        // fall thru to continue transformation
        
    default:
        Assert(source != COORDSYS_GLOBAL);
        // COORDSYS_PARENT --> COORDSYS_GLOBAL
        if(_pParentNode != NULL)
        {
            CSize globalOffset;
            _pParentNode->GetNodeTransform(
                &globalOffset,
                GetContentCoordinateSystem(),
                COORDSYS_GLOBAL);
            *pOffset += globalOffset;
        }
        break;
    }
}