]> source.dussan.org Git - poi.git/commitdiff
[bug-67735] Add Complex scripts support in XWPFRun. Thanks to Mohammed Alhaddar....
authorPJ Fanning <fanningpj@apache.org>
Sat, 14 Oct 2023 14:31:52 +0000 (14:31 +0000)
committerPJ Fanning <fanningpj@apache.org>
Sat, 14 Oct 2023 14:31:52 +0000 (14:31 +0000)
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1912963 13f79535-47bb-0310-9956-ffa450edef68

poi-ooxml/src/main/java/org/apache/poi/xwpf/usermodel/XWPFRun.java
poi-ooxml/src/test/java/org/apache/poi/xwpf/usermodel/TestXWPFRun.java

index a8a1af4ca9392ec6c860c260dc928d0d4852fa9e..e86ca8572071fc7153c5c623216f2a4314934764 100644 (file)
@@ -252,7 +252,7 @@ public class XWPFRun implements ISDTContents, IRunElement, CharacterRun {
      * Whether the bold property shall be applied to all non-complex script
      * characters in the contents of this run when displayed in a document
      *
-     * @return {@code true} if the bold property is applied
+     * @return {@code true} if the bold property for non-complex scripts is applied
      */
     @Override
     public boolean isBold() {
@@ -261,7 +261,19 @@ public class XWPFRun implements ISDTContents, IRunElement, CharacterRun {
     }
 
     /**
-     * Whether the bold property shall be applied to all non-complex script
+     * Whether the bold property shall be applied to the complex
+     * characters in the contents of this run when displayed in a document.
+     *
+     * @return {@code true} if the bold property for complex scripts is applied
+     * @since POI 5.2.5
+     */
+    public boolean isComplexScriptBold() {
+        CTRPr pr = getRunProperties(false);
+        return pr != null && pr.sizeOfBCsArray() > 0 && isCTOnOff(pr.getBCsArray(0));
+    }
+
+    /**
+     * Whether the bold property shall be applied to the non-complex
      * characters in the contents of this run when displayed in a document.
      * <p>
      * This formatting property is a toggle property, which specifies that its
@@ -281,8 +293,7 @@ public class XWPFRun implements ISDTContents, IRunElement, CharacterRun {
      * applied to non-complex script characters.
      * </p>
      *
-     * @param value {@code true} if the bold property is applied to
-     *              this run
+     * @param value {@code true} if the bold property is applied for non-complex characters.
      */
     @Override
     public void setBold(boolean value) {
@@ -291,6 +302,36 @@ public class XWPFRun implements ISDTContents, IRunElement, CharacterRun {
         bold.setVal(value ? STOnOff1.ON : STOnOff1.OFF);
     }
 
+    /**
+     * Whether the bold property shall be applied to the complex
+     * characters in the contents of this run when displayed in a document.
+     * <p>
+     * This formatting property is a toggle property, which specifies that its
+     * behavior differs between its use within a style definition and its use as
+     * direct formatting. When used as part of a style definition, setting this
+     * property shall toggle the current state of that property as specified up
+     * to this point in the hierarchy (i.e. applied to not applied, and vice
+     * versa). Setting it to {@code false} (or an equivalent) shall
+     * result in the current setting remaining unchanged. However, when used as
+     * direct formatting, setting this property to true or false shall set the
+     * absolute state of the resulting property.
+     * </p>
+     * <p>
+     * If this element is not present, the default value is to leave the
+     * formatting applied at previous level in the style hierarchy. If this
+     * element is never applied in the style hierarchy, then bold shall not be
+     * applied to the complex characters.
+     * </p>
+     *
+     * @param value {@code true} if the bold property is applied for complex characters
+     * @since POI 5.2.5
+     */
+    public void setComplexScriptBold(boolean value) {
+        CTRPr pr = getRunProperties(true);
+        CTOnOff bold = pr.sizeOfBCsArray() > 0 ? pr.getBCsArray(0) : pr.addNewBCs();
+        bold.setVal(value ? STOnOff1.ON : STOnOff1.OFF);
+    }
+
     /**
      * Get text color. The returned value is a string in the hex form "RRGGBB". This can be <code>null</code>.
      */
@@ -362,7 +403,7 @@ public class XWPFRun implements ISDTContents, IRunElement, CharacterRun {
      * Whether the italic property should be applied to all non-complex script
      * characters in the contents of this run when displayed in a document.
      *
-     * @return {@code true} if the italic property is applied
+     * @return {@code true} if the italic property is applied for non-complex characters.
      */
     @Override
     public boolean isItalic() {
@@ -371,8 +412,20 @@ public class XWPFRun implements ISDTContents, IRunElement, CharacterRun {
     }
 
     /**
-     * Whether the bold property shall be applied to all non-complex script
-     * characters in the contents of this run when displayed in a document
+     * Whether the italic property should be applied to the complex
+     * characters in the contents of this run when displayed in a document.
+     *
+     * @return {@code true} if the italic property is applied for complex characters.
+     * @since POI 5.2.5
+     */
+    public boolean isComplexScriptItalic() {
+        CTRPr pr = getRunProperties(false);
+        return pr != null && pr.sizeOfICsArray() > 0 && isCTOnOff(pr.getICsArray(0));
+    }
+
+    /**
+     * Whether the italic property shall be applied to the non-complex
+     * characters in the contents of this run when displayed in a document.
      * <p>
      * This formatting property is a toggle property, which specifies that its
      * behavior differs between its use within a style definition and its use as
@@ -389,8 +442,7 @@ public class XWPFRun implements ISDTContents, IRunElement, CharacterRun {
      * element is never applied in the style hierarchy, then bold shall not be
      * applied to non-complex script characters.
      *
-     * @param value {@code true} if the italic property is applied to
-     *              this run
+     * @param value {@code true} if the italic property is applied for non-complex characters.
      */
     @Override
     public void setItalic(boolean value) {
@@ -399,6 +451,34 @@ public class XWPFRun implements ISDTContents, IRunElement, CharacterRun {
         italic.setVal(value ? STOnOff1.ON : STOnOff1.OFF);
     }
 
+    /**
+     * Whether the italic property shall be applied to the complex
+     * characters in the contents of this run when displayed in a document.
+     * <p>
+     * This formatting property is a toggle property, which specifies that its
+     * behavior differs between its use within a style definition and its use as
+     * direct formatting. When used as part of a style definition, setting this
+     * property shall toggle the current state of that property as specified up
+     * to this point in the hierarchy (i.e. applied to not applied, and vice
+     * versa). Setting it to {@code false} (or an equivalent) shall
+     * result in the current setting remaining unchanged. However, when used as
+     * direct formatting, setting this property to true or false shall set the
+     * absolute state of the resulting property.
+     * <p>
+     * If this element is not present, the default value is to leave the
+     * formatting applied at previous level in the style hierarchy. If this
+     * element is never applied in the style hierarchy, then italic shall not be
+     * applied to the complex characters.
+     *
+     * @param value {@code true} if the italic property is applied for complex characters.
+     * @since POI 5.2.5
+     */
+    public void setComplexScriptItalic(boolean value) {
+        CTRPr pr = getRunProperties(true);
+        CTOnOff italic = pr.sizeOfICsArray() > 0 ? pr.getICsArray(0) : pr.addNewICs();
+        italic.setVal(value ? STOnOff1.ON : STOnOff1.OFF);
+    }
+
     /**
      * Get the underline setting for the run.
      *
@@ -849,7 +929,7 @@ public class XWPFRun implements ISDTContents, IRunElement, CharacterRun {
     }
 
     /**
-     * Specifies the font size which shall be applied to all non complex script
+     * Specifies the font size which shall be applied to the non-complex
      * characters in the contents of this run when displayed.
      *
      * @return value representing the font size (can be null if size not set)
@@ -861,11 +941,31 @@ public class XWPFRun implements ISDTContents, IRunElement, CharacterRun {
         return bd == null ? null : bd.doubleValue();
     }
 
+    /**
+     * Specifies the font size which shall be applied to the complex script
+     * characters in the contents of this run when displayed.
+     *
+     * @return value representing the font size for the complex scripts (can be null if size not set)
+     * @since POI 5.2.5
+     */
+    public Double getComplexScriptFontSizeAsDouble() {
+        BigDecimal bd = getComplexScriptFontSizeAsBigDecimal(1);
+        return bd == null ? null : bd.doubleValue();
+    }
+
+
     private BigDecimal getFontSizeAsBigDecimal(int scale) {
         CTRPr pr = getRunProperties(false);
         return (pr != null && pr.sizeOfSzArray() > 0)
-            ? BigDecimal.valueOf(Units.toPoints(POIXMLUnits.parseLength(pr.getSzArray(0).xgetVal()))).divide(BigDecimal.valueOf(4), scale, RoundingMode.HALF_UP)
-            : null;
+                ? BigDecimal.valueOf(Units.toPoints(POIXMLUnits.parseLength(pr.getSzArray(0).xgetVal()))).divide(BigDecimal.valueOf(4), scale, RoundingMode.HALF_UP)
+                : null;
+    }
+
+    private BigDecimal getComplexScriptFontSizeAsBigDecimal(int scale) {
+        CTRPr pr = getRunProperties(false);
+        return (pr != null && pr.sizeOfSzCsArray() > 0)
+                ? BigDecimal.valueOf(Units.toPoints(POIXMLUnits.parseLength(pr.getSzCsArray(0).xgetVal()))).divide(BigDecimal.valueOf(4), scale, RoundingMode.HALF_UP)
+                : null;
     }
 
     /**
@@ -890,8 +990,30 @@ public class XWPFRun implements ISDTContents, IRunElement, CharacterRun {
     }
 
     /**
-     * Specifies the font size which shall be applied to all non complex script
+     * Specifies the font size which shall be applied to the currently specified complex
+     * script characters in the contents of this run when displayed.
+     * <p>
+     * If this element is not present, the default value is to leave the value
+     * applied at previous level in the style hierarchy. If this element is
+     * never applied in the style hierarchy, then any appropriate font size may
+     * be used for the non-complex characters.
+     * </p>
+     *
+     * @param size The font size as number of point measurements.
+     * @see #setComplexScriptFontSize(double)
+     * @since POI 5.2.5
+     */
+    public void setComplexScriptFontSize(int size) {
+        CTRPr pr = getRunProperties(true);
+        BigInteger bint = BigInteger.valueOf(size);
+        CTHpsMeasure ctCsSize = pr.sizeOfSzCsArray() > 0 ? pr.getSzCsArray(0) : pr.addNewSzCs();
+        ctCsSize.setVal(bint.multiply(BigInteger.valueOf(2)));
+    }
+
+    /**
+     * Specifies the font size which shall be applied to the currently specified non-complex
      * characters in the contents of this run when displayed.
+     *
      * <p>
      * If this element is not present, the default value is to leave the value
      * applied at previous level in the style hierarchy. If this element is
@@ -911,6 +1033,29 @@ public class XWPFRun implements ISDTContents, IRunElement, CharacterRun {
         ctSize.setVal(bd.multiply(BigDecimal.valueOf(2)).setScale(0, RoundingMode.HALF_UP).toBigInteger());
     }
 
+
+    /**
+     * Specifies the font size which shall be applied to the currently specified complex
+     * characters in the contents of this run when displayed.
+     *
+     * <p>
+     * If this element is not present, the default value is to leave the value
+     * applied at previous level in the style hierarchy. If this element is
+     * never applied in the style hierarchy, then any appropriate font size may
+     * be used for the non-complex characters.
+     * </p>
+     *
+     * @param size The font size as number of point measurements.
+     * @see #setFontSize(int)
+     * @since POI 5.2.5
+     */
+    public void setComplexScriptFontSize(double size) {
+        CTRPr pr = getRunProperties(true);
+        BigDecimal bd = BigDecimal.valueOf(size);
+        CTHpsMeasure ctCsSize = pr.sizeOfSzCsArray() > 0 ? pr.getSzCsArray(0) : pr.addNewSzCs();
+        ctCsSize.setVal(bd.multiply(BigDecimal.valueOf(2)).setScale(0, RoundingMode.HALF_UP).toBigInteger());
+    }
+
     /**
      * This element specifies the amount by which text shall be raised or
      * lowered for this run in relation to the default baseline of the
@@ -1250,7 +1395,7 @@ public class XWPFRun implements ISDTContents, IRunElement, CharacterRun {
     public void setStyle(String styleId) {
         CTRPr pr = getCTR().getRPr();
         if (null == pr) {
-           pr = getCTR().addNewRPr();
+            pr = getCTR().addNewRPr();
         }
         CTString style = pr.sizeOfRStyleArray() > 0 ? pr.getRStyleArray(0) : pr.addNewRStyle();
         style.setVal(styleId);
index dcdfa4c3b97017e2661d35e9f48fd39ef8438425..eee37446e18ede995d5590adf434b1df119939ab 100644 (file)
@@ -145,6 +145,20 @@ class TestXWPFRun {
         assertEquals("off", rpr.getBArray(0).getVal());
     }
 
+    @Test
+    void testSetGetComplexBold() {
+        CTRPr rpr = ctRun.addNewRPr();
+        rpr.addNewBCs().setVal(STOnOff1.ON);
+
+        XWPFRun run = new XWPFRun(ctRun, irb);
+        assertTrue(run.isComplexScriptBold());
+
+        run.setComplexScriptBold(false);
+        // Implementation detail: POI natively prefers <w:b w:val="false"/>,
+        // but should correctly read val="0" and val="off"
+        assertEquals("off", rpr.getBCsArray(0).getVal());
+    }
+
     @Test
     void testSetGetItalic() {
         CTRPr rpr = ctRun.addNewRPr();
@@ -157,6 +171,18 @@ class TestXWPFRun {
         assertEquals("off", rpr.getIArray(0).getVal());
     }
 
+    @Test
+    void testSetGetItalicComplex() {
+        CTRPr rpr = ctRun.addNewRPr();
+        rpr.addNewICs().setVal(STOnOff1.ON);
+
+        XWPFRun run = new XWPFRun(ctRun, irb);
+        assertTrue(run.isComplexScriptItalic());
+
+        run.setComplexScriptItalic(false);
+        assertEquals("off", rpr.getICsArray(0).getVal());
+    }
+
     @Test
     void testSetGetStrike() {
         CTRPr rpr = ctRun.addNewRPr();
@@ -213,6 +239,23 @@ class TestXWPFRun {
         assertEquals(24.5, run.getFontSizeAsDouble(), 0.01);
     }
 
+    @Test
+    void testSetGetFontSizeComplex() {
+        CTRPr rpr = ctRun.addNewRPr();
+        rpr.addNewSzCs().setVal(BigInteger.valueOf(14));
+
+        XWPFRun run = new XWPFRun(ctRun, irb);
+
+        assertEquals(7.0, run.getComplexScriptFontSizeAsDouble(), 0.01);
+
+        run.setComplexScriptFontSize(24);
+        assertEquals("48", rpr.getSzCsArray(0).getVal().toString());
+
+        run.setComplexScriptFontSize(24.5f);
+        assertEquals("49", rpr.getSzCsArray(0).getVal().toString());
+        assertEquals(24.5, run.getComplexScriptFontSizeAsDouble(), 0.01);
+    }
+
     @Test
     void testSetGetTextForegroundBackground() {
         CTRPr rpr = ctRun.addNewRPr();
@@ -561,9 +604,9 @@ class TestXWPFRun {
     void testSetFontFamily_52288() throws IOException {
         try (XWPFDocument doc = openSampleDocument("52288.docx")) {
             doc.getParagraphs().stream()
-                .flatMap(p -> p.getRuns().stream())
-                .filter(p -> p != null && p.getText(0) != null)
-                .forEach(r -> assertDoesNotThrow(() -> r.setFontFamily("Times New Roman")));
+                    .flatMap(p -> p.getRuns().stream())
+                    .filter(p -> p != null && p.getText(0) != null)
+                    .forEach(r -> assertDoesNotThrow(() -> r.setFontFamily("Times New Roman")));
         }
     }
 
@@ -573,7 +616,7 @@ class TestXWPFRun {
         try (XWPFDocument document = new XWPFDocument()) {
 
             document.createParagraph().createRun().addPicture(
-                new ByteArrayInputStream(image), Document.PICTURE_TYPE_JPEG, "test.jpg", Units.toEMU(300), Units.toEMU(100));
+                    new ByteArrayInputStream(image), Document.PICTURE_TYPE_JPEG, "test.jpg", Units.toEMU(300), Units.toEMU(100));
 
             try (XWPFDocument docBack = writeOutAndReadBack(document)) {
                 List<XWPFPicture> pictures = docBack.getParagraphArray(0).getRuns().get(0).getEmbeddedPictures();