Fix a global buffer overflow issue in CXFA_ItemLayoutProcessor::CalculatePositionedContainerPos

BUG=471991
R=tsepez@chromium.org

Review URL: https://codereview.chromium.org/1138993002
diff --git a/BUILD.gn b/BUILD.gn
index 9e05bab..b9be538 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -1560,6 +1560,7 @@
     "testing/fx_string_testhelpers.cpp",
     "testing/fx_string_testhelpers.h",
     "xfa/src/fxbarcode/pdf417/BC_PDF417HighLevelEncoder_unittest.cpp",
+    "xfa/src/fxfa/src/parser/xfa_utils_imp_unittest.cpp",
   ]
   deps = [
     "//testing/gtest",
diff --git a/pdfium.gyp b/pdfium.gyp
index 8a18909..7d712c6 100644
--- a/pdfium.gyp
+++ b/pdfium.gyp
@@ -928,6 +928,7 @@
         'testing/fx_string_testhelpers.h',
         'testing/fx_string_testhelpers.cpp',
         'xfa/src/fxbarcode/pdf417/BC_PDF417HighLevelEncoder_unittest.cpp',
+        'xfa/src/fxfa/src/parser/xfa_utils_imp_unittest.cpp',
       ],
     },
     {
diff --git a/xfa/src/fxfa/src/common/xfa_utils.h b/xfa/src/fxfa/src/common/xfa_utils.h
index c6f0c47..b666397 100644
--- a/xfa/src/fxfa/src/common/xfa_utils.h
+++ b/xfa/src/fxfa/src/common/xfa_utils.h
@@ -216,22 +216,24 @@
 class CXFA_Node;

 class CXFA_WidgetData;

 #include "fxfa_localevalue.h"

-CXFA_Node*			XFA_CreateUIChild(CXFA_Node* pNode, XFA_ELEMENT& eWidgetType);

-CXFA_LocaleValue	XFA_GetLocaleValue(CXFA_WidgetData* pWidgetData);

-CFX_WideString		XFA_NumericLimit(const CFX_WideString &wsValue, FX_INT32 iLead, FX_INT32 iTread);

-FX_DOUBLE XFA_WideStringToDouble(const CFX_WideString &wsStringVal);

-FX_DOUBLE XFA_ByteStringToDouble(FX_BSTR szStringVal);

+CXFA_Node*          XFA_CreateUIChild(CXFA_Node* pNode, XFA_ELEMENT& eWidgetType);

+CXFA_LocaleValue    XFA_GetLocaleValue(CXFA_WidgetData* pWidgetData);

+CFX_WideString	    XFA_NumericLimit(const CFX_WideString &wsValue, FX_INT32 iLead, FX_INT32 iTread);

+FX_DOUBLE           XFA_WideStringToDouble(const CFX_WideString &wsStringVal);

+FX_DOUBLE           XFA_ByteStringToDouble(FX_BSTR szStringVal);

+FX_INT32            XFA_MapRotation(FX_INT32 nRotation); 

 #ifndef XFA_PARSE_HAS_LINEIDENTIFIER

 #define XFA_PARSE_HAS_LINEIDENTIFIER

 #endif

-FX_BOOL XFA_RecognizeRichText(IFDE_XMLElement* pRichTextXMLNode);

-void	XFA_GetPlainTextFromRichText(IFDE_XMLNode *pXMLNode, CFX_WideString &wsPlainText);

-FX_BOOL XFA_FieldIsMultiListBox(CXFA_Node* pFieldNode);

-IFX_Stream* XFA_CreateWideTextRead(const CFX_WideString &wsBuffer);

-FX_BOOL		XFA_IsLayoutElement(XFA_ELEMENT eElement, FX_BOOL bLayoutContainer = FALSE);

-FX_BOOL		XFA_IsTakingupSpace(XFA_ATTRIBUTEENUM ePresence);

-FX_BOOL		XFA_IsFlowingLayout(XFA_ATTRIBUTEENUM eLayout);

-FX_BOOL		XFA_IsHorizontalFlow(XFA_ATTRIBUTEENUM eLayout);

-void		XFA_DataExporter_DealWithDataGroupNode(CXFA_Node *pDataNode);

-void		XFA_DataExporter_RegenerateFormFile(CXFA_Node* pNode, IFX_Stream* pStream, FX_LPCSTR pChecksum = NULL, FX_BOOL bSaveXML = FALSE);

+FX_BOOL             XFA_RecognizeRichText(IFDE_XMLElement* pRichTextXMLNode);

+void                XFA_GetPlainTextFromRichText(IFDE_XMLNode *pXMLNode, CFX_WideString &wsPlainText);

+FX_BOOL             XFA_FieldIsMultiListBox(CXFA_Node* pFieldNode);

+IFX_Stream*         XFA_CreateWideTextRead(const CFX_WideString &wsBuffer);

+FX_BOOL             XFA_IsLayoutElement(XFA_ELEMENT eElement, FX_BOOL bLayoutContainer = FALSE);

+FX_BOOL             XFA_IsTakingupSpace(XFA_ATTRIBUTEENUM ePresence);

+FX_BOOL             XFA_IsFlowingLayout(XFA_ATTRIBUTEENUM eLayout);

+FX_BOOL	            XFA_IsHorizontalFlow(XFA_ATTRIBUTEENUM eLayout);

+void                XFA_DataExporter_DealWithDataGroupNode(CXFA_Node *pDataNode);

+void                XFA_DataExporter_RegenerateFormFile(CXFA_Node* pNode, IFX_Stream* pStream,

+                                                        FX_LPCSTR pChecksum = NULL, FX_BOOL bSaveXML = FALSE);

 #endif

diff --git a/xfa/src/fxfa/src/parser/xfa_layout_itemlayout.cpp b/xfa/src/fxfa/src/parser/xfa_layout_itemlayout.cpp
index e6a2070..2280867 100644
--- a/xfa/src/fxfa/src/parser/xfa_layout_itemlayout.cpp
+++ b/xfa/src/fxfa/src/parser/xfa_layout_itemlayout.cpp
@@ -712,10 +712,6 @@
 }

 void CXFA_ItemLayoutProcessor::CalculatePositionedContainerPos(CXFA_Node* pNode, FX_FLOAT fWidth, FX_FLOAT fHeight, FX_FLOAT& fAbsoluteX, FX_FLOAT& fAbsoluteY)

 {

-    FX_FLOAT fAnchorX = pNode->GetMeasure(XFA_ATTRIBUTE_X).ToUnit(XFA_UNIT_Pt);

-    FX_FLOAT fAnchorY = pNode->GetMeasure(XFA_ATTRIBUTE_Y).ToUnit(XFA_UNIT_Pt);

-    FX_INT32 nRotate = FXSYS_round(pNode->GetMeasure(XFA_ATTRIBUTE_Rotate).GetValue());

-    nRotate = (nRotate < 0 ? (nRotate % 360) + 360 : nRotate % 360) / 90;

     XFA_ATTRIBUTEENUM eAnchorType = pNode->GetEnum(XFA_ATTRIBUTE_AnchorType);

     FX_INT32 nAnchorType = 0;

     switch(eAnchorType) {

@@ -749,7 +745,15 @@
         default:

             break;

     }

-    static const FX_UINT8 nNextPos[4][9] = {{0, 1, 2, 3, 4, 5, 6, 7, 8}, {6, 3, 0, 7, 4, 1, 8, 5, 2}, {8, 7, 6, 5, 4, 3, 2, 1, 0}, {2, 5, 8, 1, 4, 7, 0, 3, 6}};

+    static const FX_UINT8 nNextPos[4][9] = { {0, 1, 2, 3, 4, 5, 6, 7, 8},

+                                             {6, 3, 0, 7, 4, 1, 8, 5, 2}, 

+                                             {8, 7, 6, 5, 4, 3, 2, 1, 0},

+                                             {2, 5, 8, 1, 4, 7, 0, 3, 6} };

+

+    FX_FLOAT fAnchorX = pNode->GetMeasure(XFA_ATTRIBUTE_X).ToUnit(XFA_UNIT_Pt);

+    FX_FLOAT fAnchorY = pNode->GetMeasure(XFA_ATTRIBUTE_Y).ToUnit(XFA_UNIT_Pt);

+    FX_INT32 nRotate = FXSYS_round(pNode->GetMeasure(XFA_ATTRIBUTE_Rotate).GetValue());

+    nRotate = XFA_MapRotation(nRotate) / 90;

     FX_INT32 nAbsoluteAnchorType = nNextPos[nRotate][nAnchorType];

     fAbsoluteX = fAnchorX;

     fAbsoluteY = fAnchorY;

@@ -2297,7 +2301,7 @@
     FX_FLOAT fWidth = -1;

     pNotify->StartFieldDrawLayout(m_pFormNode, fWidth, fHeight);

     FX_INT32 nRotate = FXSYS_round(m_pFormNode->GetMeasure(XFA_ATTRIBUTE_Rotate).GetValue());

-    nRotate = (nRotate < 0 ? (nRotate % 360) + 360 : nRotate % 360);

+    nRotate = XFA_MapRotation(nRotate);

     if(nRotate == 90 || nRotate == 270) {

         FX_FLOAT fTmp = fWidth;

         fWidth = fHeight;

diff --git a/xfa/src/fxfa/src/parser/xfa_objectacc_imp.cpp b/xfa/src/fxfa/src/parser/xfa_objectacc_imp.cpp
index c3bcd5e..c6ece36 100644
--- a/xfa/src/fxfa/src/parser/xfa_objectacc_imp.cpp
+++ b/xfa/src/fxfa/src/parser/xfa_objectacc_imp.cpp
@@ -1792,7 +1792,7 @@
         return 0;

     }

     FX_INT32 iRotate =  FXSYS_round(ms.GetValue());

-    iRotate = (iRotate < 0 ? (iRotate % 360) + 360 : iRotate % 360);

+    iRotate = XFA_MapRotation(iRotate);

     return iRotate / 90 * 90;

 }

 CXFA_Border CXFA_WidgetData::GetBorder(FX_BOOL bModified)

@@ -1933,12 +1933,7 @@
 }

 FX_BOOL CXFA_WidgetData::SetRotate(FX_INT32 iRotate)

 {

-    while (iRotate < 0) {

-        iRotate += 360;

-    }

-    while (iRotate >= 360) {

-        iRotate -= 360;

-    }

+    iRotate = XFA_MapRotation(iRotate);

     CXFA_Measurement ms((FX_FLOAT)iRotate, XFA_UNIT_Angle);

     return m_pNode->SetMeasure(XFA_ATTRIBUTE_Rotate, ms);

 }

diff --git a/xfa/src/fxfa/src/parser/xfa_utils_imp.cpp b/xfa/src/fxfa/src/parser/xfa_utils_imp.cpp
index 9c7ca9c..e4f7545 100644
--- a/xfa/src/fxfa/src/parser/xfa_utils_imp.cpp
+++ b/xfa/src/fxfa/src/parser/xfa_utils_imp.cpp
@@ -375,8 +375,16 @@
     }

     return dValue;

 }

+

 FX_DOUBLE XFA_ByteStringToDouble(FX_BSTR szStringVal)

 {

     CFX_WideString wsValue = CFX_WideString::FromUTF8(szStringVal.GetCStr(), szStringVal.GetLength());

     return XFA_WideStringToDouble(wsValue);

 }

+

+FX_INT32 XFA_MapRotation(FX_INT32 nRotation) {

+    nRotation = nRotation % 360;

+    nRotation = nRotation < 0 ? nRotation + 360 : nRotation;

+    return nRotation;

+}

+

diff --git a/xfa/src/fxfa/src/parser/xfa_utils_imp_unittest.cpp b/xfa/src/fxfa/src/parser/xfa_utils_imp_unittest.cpp
new file mode 100644
index 0000000..a969872
--- /dev/null
+++ b/xfa/src/fxfa/src/parser/xfa_utils_imp_unittest.cpp
@@ -0,0 +1,36 @@
+// Copyright 2014 PDFium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "../../../testing/gtest/include/gtest/gtest.h"
+#include "../../../foxitlib.h"
+#include "../common/xfa_utils.h"
+
+TEST(XfaUtilsImp, XFA_MapRotation) {
+    struct TestCase {
+        int input;
+        int expected_output;
+    } TestCases[] = {
+        {-1000000, 80},
+        {-361, 359},
+        {-360, 0},
+        {-359, 1},
+        {-91, 269},
+        {-90, 270},
+        {-89, 271},
+        {-1, 359},
+        {0, 0},
+        {1, 1},
+        {89, 89},
+        {90, 90},
+        {91, 91},
+        {359, 359},
+        {360, 0},
+        {361, 1},
+        {100000, 280}
+    };                             
+
+    for (size_t i = 0; i < FX_ArraySize(TestCases); ++i) {
+        EXPECT_EQ(TestCases[i].expected_output, XFA_MapRotation(TestCases[i].input));
+    }
+}