boolean isInvalid(StringBlock block, float gap) { if (isHead() || isTail()) return false; if (x0 == Integer.MIN_VALUE || y0 == Integer.MIN_VALUE) { return true; } Rectangle bound = block.getTextBox(); if (bound == null) { return false; } return x0 > 0 && bound.x + bound.width - gap < getX1(); }
public static ARSCFile read(IntReader reader) throws IOException { ARSCFile arsc = new ARSCFile(); ReadUtil.readCheckType(reader, ARSC_CHUNK_TYPE); /* size */ reader.readInt(); int groupCount = reader.readInt(); if (groupCount != 1) { throw new IOException("Only one package per file is supported."); } arsc.strings = StringBlock.read(reader); arsc.pkges = new Pkge[1]; arsc.pkges[0] = readPackage(arsc, reader); return arsc; }
private Rectangle getBound(StringBlock block) { if (block.getTextBox() != null) { return block.getTextBox(); } return UNBOUNDED; }
void update(StringBlock block) { final float[] tabs = block.getTabPosition(); final float tabWidth = block.getTabWidth(); final Rectangle bound = getBound(block); sizeScale = block.getSize() / font.getCharSet().getRenderedSize(); lineY = computeLineY(block); if (isHead()) { x0 = getBound(block).x; y0 = lineY; width = 0; height = 0; xAdvance = 0; } else if (isTab()) { x0 = previous.getNextX(); width = tabWidth; y0 = lineY; height = 0; if (tabs != null && x0 < tabs[tabs.length - 1]) { for (int i = 0; i < tabs.length - 1; i++) { if (x0 > tabs[i] && x0 < tabs[i + 1]) { width = tabs[i + 1] - x0; } } } xAdvance = width; } else if (bitmapChar == null) { x0 = getPrevious().getX1(); y0 = lineY; width = 0; height = 0; xAdvance = 0; } else { float xOffset = bitmapChar.getXOffset() * sizeScale; float yOffset = bitmapChar.getYOffset() * sizeScale; xAdvance = bitmapChar.getXAdvance() * sizeScale; width = bitmapChar.getWidth() * sizeScale; height = bitmapChar.getHeight() * sizeScale; float incrScale = rightToLeft ? -1f : 1f; float kernAmount = 0f; if (previous.isHead() || previous.eol) { x0 = bound.x; // The first letter quad will be drawn right at the first // position... but it does not offset by the characters offset // amount. This means that we've potentially accumulated extra // pixels and the next letter won't get drawn far enough unless // we add this offset back into xAdvance.. by subtracting it. // This is the same thing that's done below because we've // technically baked the offset in just like below. It doesn't // look like it at first glance so I'm keeping it separate with // this comment. xAdvance -= xOffset * incrScale; } else { x0 = previous.getNextX() + xOffset * incrScale; // Since x0 will have offset baked into it then we // need to counteract that in xAdvance. This is better // than removing it in getNextX() because we also need // to take kerning into account below... which will also // get baked in. // Without this, getNextX() will return values too far to // the left, for example. xAdvance -= xOffset * incrScale; } y0 = lineY + LINE_DIR * yOffset; // Adjust for kerning BitmapCharacter lastChar = previous.getBitmapChar(); if (lastChar != null && block.isKerning()) { kernAmount = lastChar.getKerning(c) * sizeScale; x0 += kernAmount * incrScale; // Need to unbake the kerning from xAdvance since it // is baked into x0... see above. // xAdvance -= kernAmount * incrScale; // No, kerning is an inter-character spacing and _does_ affect // all subsequent cursor positions. } } if (isEndOfLine()) { xAdvance = bound.x - x0; } }
/** * Gets the line height of a StringBlock. * * @param sb * @return */ public float getLineHeight(StringBlock sb) { return charSet.getLineHeight() * (sb.getSize() / charSet.getRenderedSize()); }
private final void doNext() throws IOException { // Delayed initialization. if (m_strings == null) { ChunkUtil.readCheckType(m_reader, CHUNK_AXML_FILE); /* chunkSize */ m_reader.skipInt(); m_strings = StringBlock.read(m_reader); m_namespaces.increaseDepth(); m_operational = true; } if (m_event == END_DOCUMENT) { return; } int event = m_event; resetEventInfo(); while (true) { if (m_decreaseDepth) { m_decreaseDepth = false; m_namespaces.decreaseDepth(); } // Fake END_DOCUMENT event. if (event == END_TAG && m_namespaces.getDepth() == 1 && m_namespaces.getCurrentCount() == 0) { m_event = END_DOCUMENT; break; } int chunkType; if (event == START_DOCUMENT) { // Fake event, see CHUNK_XML_START_TAG handler. chunkType = CHUNK_XML_START_TAG; } else { chunkType = m_reader.readInt(); } if (chunkType == CHUNK_RESOURCEIDS) { int chunkSize = m_reader.readInt(); if (chunkSize < 8 || (chunkSize % 4) != 0) { throw new IOException("Invalid resource ids size (" + chunkSize + ")."); } m_resourceIDs = m_reader.readIntArray(chunkSize / 4 - 2); continue; } if (chunkType < CHUNK_XML_FIRST || chunkType > CHUNK_XML_LAST) { throw new IOException("Invalid chunk type (" + chunkType + ")."); } // Fake START_DOCUMENT event. if (chunkType == CHUNK_XML_START_TAG && event == -1) { m_event = START_DOCUMENT; break; } // Common header. /* chunkSize */ m_reader.skipInt(); int lineNumber = m_reader.readInt(); /* 0xFFFFFFFF */ m_reader.skipInt(); if (chunkType == CHUNK_XML_START_NAMESPACE || chunkType == CHUNK_XML_END_NAMESPACE) { if (chunkType == CHUNK_XML_START_NAMESPACE) { int prefix = m_reader.readInt(); int uri = m_reader.readInt(); m_namespaces.push(prefix, uri); } else { /* prefix */ m_reader.skipInt(); /* uri */ m_reader.skipInt(); m_namespaces.pop(); } continue; } m_lineNumber = lineNumber; if (chunkType == CHUNK_XML_START_TAG) { m_namespaceUri = m_reader.readInt(); m_name = m_reader.readInt(); /* flags? */ m_reader.skipInt(); int attributeCount = m_reader.readInt(); m_idAttribute = (attributeCount >>> 16) - 1; attributeCount &= 0xFFFF; m_classAttribute = m_reader.readInt(); m_styleAttribute = (m_classAttribute >>> 16) - 1; m_classAttribute = (m_classAttribute & 0xFFFF) - 1; m_attributes = m_reader.readIntArray(attributeCount * ATTRIBUTE_LENGHT); for (int i = ATTRIBUTE_IX_VALUE_TYPE; i < m_attributes.length; ) { m_attributes[i] = (m_attributes[i] >>> 24); i += ATTRIBUTE_LENGHT; } m_namespaces.increaseDepth(); m_event = START_TAG; break; } if (chunkType == CHUNK_XML_END_TAG) { m_namespaceUri = m_reader.readInt(); m_name = m_reader.readInt(); m_event = END_TAG; m_decreaseDepth = true; break; } if (chunkType == CHUNK_XML_TEXT) { m_name = m_reader.readInt(); /* ? */ m_reader.skipInt(); /* ? */ m_reader.skipInt(); m_event = TEXT; break; } } }
private static Pkge readPackage(ARSCFile file, IntReader reader) throws IOException { Pkge pkge = new Pkge(); pkge.file = file; ReadUtil.readCheckType(reader, PACKAGE_CHUNK_TYPE); /* size */ reader.skipInt(); pkge.id = reader.readInt(); { final int nameLength = 128; StringBuilder name = new StringBuilder(16); int i = 0; for (; i != nameLength; ) { ++i; int ch = reader.readShort(); if (ch == 0) { break; } name.append((char) ch); } reader.skip((nameLength - i) * 2); reader.skip((nameLength * 2) % 4); pkge.name = name.toString(); } /* signature? */ reader.skipInt(); int assetCount = reader.readInt(); /* idNamesOffset */ reader.skipInt(); /* idNamesCount */ reader.skipInt(); pkge.assetNames = StringBlock.read(reader); pkge.resourceNames = StringBlock.read(reader); pkge.assets = new Asset[assetCount]; ArrayList contents = new ArrayList(); int assetsRead = 0; Asset currentAsset = null; while (reader.available() != 0) { int chunkType = reader.readInt(); if (chunkType != CONTENT_CHUNK_TYPE) { if (currentAsset != null) { currentAsset.contents = new Content[contents.size()]; contents.toArray(currentAsset.contents); contents.clear(); } } if (chunkType == ASSET_CHUNK_TYPE) { currentAsset = readAsset(reader, pkge); pkge.assets[assetsRead] = currentAsset; assetsRead += 1; } else if (chunkType == CONTENT_CHUNK_TYPE) { if (currentAsset == null) { throw new IOException("Invalid chunk sequence: content read before asset."); } contents.add(readContent(reader, currentAsset)); } else { throw new IOException("Unexpected chunk type (" + chunkType + ")."); } } if (currentAsset != null) { currentAsset.contents = new Content[contents.size()]; contents.toArray(currentAsset.contents); contents.clear(); } if (assetsRead != assetCount) { throw new IOException("Not all assets where read (" + (assetCount - assetsRead) + " left)."); } return pkge; }