123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573 |
- /*
- * ====================================================================
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- * ====================================================================
- */
-
- package org.apache.poi.sl.draw.geom;
-
- import java.util.HashMap;
- import java.util.Map;
- import java.util.function.BiConsumer;
-
- import javax.xml.stream.XMLStreamConstants;
- import javax.xml.stream.XMLStreamException;
- import javax.xml.stream.XMLStreamReader;
-
- import org.apache.logging.log4j.LogManager;
- import org.apache.logging.log4j.Logger;
- import org.apache.poi.sl.usermodel.PaintStyle.PaintModifier;
- import org.apache.poi.util.Internal;
-
- @Internal
- class PresetParser {
- enum Mode {
- FILE(PresetParser::updateFile),
- SHAPE_LST(PresetParser::updateShapeList),
- SHAPE(PresetParser::updateShape),
- GUIDE_LST(PresetParser::updateGuideList),
- AH_LST(PresetParser::updateAhList),
- CXN_LST(PresetParser::updateCxnList),
- PATH_LST(PresetParser::updatePathLst),
- PATH(PresetParser::updatePath);
-
- interface Handler {
- void update(PresetParser parser, XMLStreamReader sr) throws XMLStreamException;
- }
-
- final Handler handler;
-
- Mode(Handler handler) {
- this.handler = handler;
- }
- }
-
- private static final Logger LOG = LogManager.getLogger(PresetParser.class);
-
- private Mode mode;
-
- private final Map<String, CustomGeometry> geom = new HashMap<>();
- private CustomGeometry customGeometry;
- private boolean useAdjustValue;
- private Path path;
-
-
- PresetParser(Mode mode) {
- this.mode = mode;
- if (mode == Mode.SHAPE) {
- customGeometry = new CustomGeometry();
- geom.put("custom", customGeometry);
- }
- }
-
- void parse(XMLStreamReader sr) throws XMLStreamException {
- while (sr.hasNext()) {
- switch (sr.next()) {
- case XMLStreamConstants.START_ELEMENT:
- mode.handler.update(this, sr);
- break;
- case XMLStreamConstants.END_ELEMENT:
- endContext();
- break;
- case XMLStreamConstants.END_DOCUMENT:
- return;
- default:
- break;
- }
- }
- }
-
- Map<String, CustomGeometry> getGeom() {
- return geom;
- }
-
- private void updateFile(XMLStreamReader sr) {
- final String name = sr.getLocalName();
- assert("presetShapeDefinitons".equals(name));
- mode = Mode.SHAPE_LST;
- }
-
- private void updateShapeList(XMLStreamReader sr) {
- final String name = sr.getLocalName();
- customGeometry = new CustomGeometry();
- if (geom.containsKey(name)) {
- LOG.atWarn().log("Duplicate definition of {}", name);
- }
- geom.put(name, customGeometry);
- mode = Mode.SHAPE;
- }
-
- private void updateShape(XMLStreamReader sr) throws XMLStreamException {
- final String name = sr.getLocalName();
- switch (name) {
- case "avLst":
- useAdjustValue = true;
- mode = Mode.GUIDE_LST;
- break;
- case "gdLst":
- useAdjustValue = false;
- mode = Mode.GUIDE_LST;
- break;
- case "ahLst":
- mode = Mode.AH_LST;
- break;
- case "cxnLst":
- mode = Mode.CXN_LST;
- break;
- case "rect":
- addRectangle(sr);
- break;
- case "pathLst":
- mode = Mode.PATH_LST;
- break;
- }
- }
-
- private void updateGuideList(XMLStreamReader sr) throws XMLStreamException {
- final String name = sr.getLocalName();
- assert("gd".equals(name));
- final Guide gd;
- if (useAdjustValue) {
- customGeometry.addAdjustGuide((AdjustValue)(gd = new AdjustValue()));
- } else {
- customGeometry.addGeomGuide(gd = new Guide());
- }
-
- parseAttributes(sr, (key,val) -> {
- switch (key) {
- case "name":
- // CollapsedStringAdapter
- gd.setName(collapseString(val));
- break;
- case "fmla":
- gd.setFmla(val);
- break;
- }
- });
-
- int tag = nextTag(sr);
- assert(tag == XMLStreamConstants.END_ELEMENT);
- }
-
-
- private void updateAhList(XMLStreamReader sr) throws XMLStreamException {
- String name = sr.getLocalName();
- switch (name) {
- case "ahXY":
- addXY(sr);
- break;
-
- case "ahPolar":
- addPolar(sr);
- break;
- }
- }
-
- private void addXY(XMLStreamReader sr) throws XMLStreamException {
- XYAdjustHandle ahXY = new XYAdjustHandle();
- customGeometry.addAdjustHandle(ahXY);
-
- parseAttributes(sr, (key, val) -> {
- switch (key) {
- case "gdRefX":
- ahXY.setGdRefX(collapseString(val));
- break;
- case "minX":
- ahXY.setMinX(val);
- break;
- case "maxX":
- ahXY.setMaxX(val);
- break;
- case "gdRefY":
- ahXY.setGdRefY(collapseString(val));
- break;
- case "minY":
- ahXY.setMinY(val);
- break;
- case "maxY":
- ahXY.setMaxY(val);
- break;
- }
- });
-
- ahXY.setPos(parsePosPoint(sr));
- }
-
- private void addPolar(XMLStreamReader sr) throws XMLStreamException {
- PolarAdjustHandle ahPolar = new PolarAdjustHandle();
- customGeometry.addAdjustHandle(ahPolar);
-
- parseAttributes(sr, (key, val) -> {
- switch (key) {
- case "gdRefR":
- ahPolar.setGdRefR(collapseString(val));
- break;
- case "minR":
- ahPolar.setMinR(val);
- break;
- case "maxR":
- ahPolar.setMaxR(val);
- break;
- case "gdRefAng":
- ahPolar.setGdRefAng(collapseString(val));
- break;
- case "minAng":
- ahPolar.setMinAng(val);
- break;
- case "maxAng":
- ahPolar.setMaxAng(val);
- break;
- }
- });
-
- ahPolar.setPos(parsePosPoint(sr));
- }
-
- private void updateCxnList(XMLStreamReader sr) throws XMLStreamException {
- String name = sr.getLocalName();
- assert("cxn".equals(name));
-
- ConnectionSite cxn = new ConnectionSite();
- customGeometry.addConnectionSite(cxn);
-
- parseAttributes(sr, (key, val) -> {
- if ("ang".equals(key)) {
- cxn.setAng(val);
- }
- });
-
- cxn.setPos(parsePosPoint(sr));
- }
-
- private void updatePathLst(XMLStreamReader sr) {
- String name = sr.getLocalName();
- assert("path".equals(name));
-
- path = new Path();
- customGeometry.addPath(path);
-
- parseAttributes(sr, (key, val) -> {
- switch (key) {
- case "w":
- path.setW(Long.parseLong(val));
- break;
- case "h":
- path.setH(Long.parseLong(val));
- break;
- case "fill":
- path.setFill(mapFill(val));
- break;
- case "stroke":
- path.setStroke(Boolean.parseBoolean(val));
- break;
- case "extrusionOk":
- path.setExtrusionOk(Boolean.parseBoolean(val));
- break;
- }
- });
-
- mode = Mode.PATH;
- }
-
- private static PaintModifier mapFill(String fill) {
- switch (fill) {
- default:
- case "none":
- return PaintModifier.NONE;
- case "norm":
- return PaintModifier.NORM;
- case "lighten":
- return PaintModifier.LIGHTEN;
- case "lightenLess":
- return PaintModifier.LIGHTEN_LESS;
- case "darken":
- return PaintModifier.DARKEN;
- case "darkenLess":
- return PaintModifier.DARKEN_LESS;
- }
- }
-
- private void updatePath(XMLStreamReader sr) throws XMLStreamException {
- String name = sr.getLocalName();
- switch (name) {
- case "close":
- closePath(sr);
- break;
- case "moveTo":
- moveTo(sr);
- break;
- case "lnTo":
- lineTo(sr);
- break;
- case "arcTo":
- arcTo(sr);
- break;
- case "quadBezTo":
- quadBezTo(sr);
- break;
- case "cubicBezTo":
- cubicBezTo(sr);
- break;
- }
- }
-
- private void closePath(XMLStreamReader sr) throws XMLStreamException {
- path.addCommand(new ClosePathCommand());
- int tag = nextTag(sr);
- assert(tag == XMLStreamConstants.END_ELEMENT);
- }
-
- private void moveTo(XMLStreamReader sr) throws XMLStreamException {
- MoveToCommand cmd = new MoveToCommand();
- path.addCommand(cmd);
-
- AdjustPoint pt = parsePtPoint(sr, true);
- assert(pt != null);
- cmd.setPt(pt);
- }
-
- private void lineTo(XMLStreamReader sr) throws XMLStreamException {
- LineToCommand cmd = new LineToCommand();
- path.addCommand(cmd);
-
- AdjustPoint pt = parsePtPoint(sr, true);
- assert(pt != null);
- cmd.setPt(pt);
- }
-
- private void arcTo(XMLStreamReader sr) throws XMLStreamException {
- ArcToCommand cmd = new ArcToCommand();
- path.addCommand(cmd);
- parseAttributes(sr, (key, val) -> {
- switch (key) {
- case "wR":
- cmd.setWR(val);
- break;
- case "hR":
- cmd.setHR(val);
- break;
- case "stAng":
- cmd.setStAng(val);
- break;
- case "swAng":
- cmd.setSwAng(val);
- break;
- }
- });
- int tag = nextTag(sr);
- assert (tag == XMLStreamConstants.END_ELEMENT);
- }
-
- private void quadBezTo(XMLStreamReader sr) throws XMLStreamException {
- QuadToCommand cmd = new QuadToCommand();
- path.addCommand(cmd);
- AdjustPoint pt1 = parsePtPoint(sr, false);
- AdjustPoint pt2 = parsePtPoint(sr, true);
- assert (pt1 != null && pt2 != null);
- cmd.setPt1(pt1);
- cmd.setPt2(pt2);
- }
-
- private void cubicBezTo(XMLStreamReader sr) throws XMLStreamException {
- CurveToCommand cmd = new CurveToCommand();
- path.addCommand(cmd);
- AdjustPoint pt1 = parsePtPoint(sr, false);
- AdjustPoint pt2 = parsePtPoint(sr, false);
- AdjustPoint pt3 = parsePtPoint(sr, true);
- assert (pt1 != null && pt2 != null && pt3 != null);
- cmd.setPt1(pt1);
- cmd.setPt2(pt2);
- cmd.setPt3(pt3);
- }
-
- private void addRectangle(XMLStreamReader sr) throws XMLStreamException {
- String[] ltrb = new String[4];
- parseAttributes(sr, (key,val) -> {
- switch (key) {
- case "l":
- ltrb[0] = val;
- break;
- case "t":
- ltrb[1] = val;
- break;
- case "r":
- ltrb[2] = val;
- break;
- case "b":
- ltrb[3] = val;
- break;
- }
- });
-
- customGeometry.setTextBounds(ltrb[0],ltrb[1],ltrb[2],ltrb[3]);
-
- int tag = nextTag(sr);
- assert(tag == XMLStreamConstants.END_ELEMENT);
- }
-
-
- private void endContext() {
- switch (mode) {
- case FILE:
- case SHAPE_LST:
- mode = Mode.FILE;
- break;
- case SHAPE:
- mode = Mode.SHAPE_LST;
- break;
- case CXN_LST:
- case AH_LST:
- case GUIDE_LST:
- case PATH_LST:
- useAdjustValue = false;
- path = null;
- mode = Mode.SHAPE;
- break;
- case PATH:
- path = null;
- mode = Mode.PATH_LST;
- break;
- }
- }
-
- private AdjustPoint parsePosPoint(XMLStreamReader sr) throws XMLStreamException {
- return parseAdjPoint(sr, true, "pos");
- }
-
- private AdjustPoint parsePtPoint(XMLStreamReader sr, boolean closeOuter) throws XMLStreamException {
- return parseAdjPoint(sr, closeOuter, "pt");
- }
-
- private AdjustPoint parseAdjPoint(XMLStreamReader sr, boolean closeOuter, String name) throws XMLStreamException {
- int tag = nextTag(sr);
- if (tag == XMLStreamConstants.END_ELEMENT) {
- return null;
- }
-
- assert (name.equals(sr.getLocalName()));
-
- AdjustPoint pos = new AdjustPoint();
- parseAttributes(sr, (key, val) -> {
- switch (key) {
- case "x":
- pos.setX(val);
- break;
- case "y":
- pos.setY(val);
- break;
- }
- });
- tag = nextTag(sr);
- assert(tag == XMLStreamConstants.END_ELEMENT);
- if (closeOuter) {
- tag = nextTag(sr);
- assert(tag == XMLStreamConstants.END_ELEMENT);
- }
- return pos;
- }
-
- private void parseAttributes(XMLStreamReader sr, BiConsumer<String,String> c) {
- for (int i=0; i<sr.getAttributeCount(); i++) {
- c.accept(sr.getAttributeLocalName(i), sr.getAttributeValue(i));
- }
- }
-
- /**
- * Reimplement {@link XMLStreamReader#nextTag()} because of differences of XmlBeans and Xerces XMLStreamReader.
- * XmlBeans doesn't return the END_ELEMENT on nextTag()
- *
- * @param sr the stream reader
- * @return the next tag type (START_ELEMENT, END_ELEMENT, END_DOCUMENT)
- * @throws XMLStreamException if reading the next tag fails
- */
- private static int nextTag(XMLStreamReader sr) throws XMLStreamException {
- int tag;
- do {
- tag = sr.next();
- } while (
- tag != XMLStreamConstants.START_ELEMENT &&
- tag != XMLStreamConstants.END_ELEMENT &&
- tag != XMLStreamConstants.END_DOCUMENT
- );
- return tag;
- }
-
- /**
- * Removes leading and trailing whitespaces of the string given as the parameter, then truncate any
- * sequence of tab, CR, LF, and SP by a single whitespace character ' '.
- */
- private static String collapseString(String text) {
- if (text==null) {
- return null;
- }
-
- int len = text.length();
-
- // most of the texts are already in the collapsed form. so look for the first whitespace in the hope that we
- // will never see it.
- int s;
- for (s=0; s<len; s++) {
- if (isWhiteSpace(text.charAt(s))) {
- break;
- }
- }
-
- if (s == len) {
- // the input happens to be already collapsed.
- return text;
- }
-
- // we now know that the input contains spaces. let's sit down and do the collapsing normally.
- // allocate enough size to avoid re-allocation
- StringBuilder result = new StringBuilder(len);
-
- if (s != 0) {
- for(int i=0; i<s; i++) {
- result.append(text.charAt(i));
- }
- result.append(' ');
- }
-
- boolean inStripMode = true;
- for (int i = s+1; i < len; i++) {
- char ch = text.charAt(i);
- boolean b = isWhiteSpace(ch);
-
- if (inStripMode && b) {
- // skip this character
- continue;
- }
-
- inStripMode = b;
- result.append(inStripMode ? ' ' : ch);
- }
-
- // remove trailing whitespaces
- len = result.length();
- if (len > 0 && result.charAt(len - 1) == ' ') {
- result.setLength(len - 1);
- }
-
- // whitespaces are already collapsed, so all we have to do is
- // to remove the last one character if it's a whitespace.
- return result.toString();
- }
-
- /** returns true if the specified char is a white space character. */
- private static boolean isWhiteSpace(char ch) {
- return ch == 0x9 || ch == 0xA || ch == 0xD || ch == 0x20;
- }
- }
|