1
0
Fork 0
mirror of https://github.com/geometer/FBReaderJ.git synced 2025-10-05 19:42:17 +02:00

full-screen cover images

Conflicts:

	ChangeLog
This commit is contained in:
Nikolay Pultsin 2011-12-28 02:31:14 +00:00
parent d30ba1a9d8
commit 9787e2db11
22 changed files with 307 additions and 118 deletions

View file

@ -6,6 +6,7 @@
* Option for disabling button lights in Android 3/4 has been introduced * Option for disabling button lights in Android 3/4 has been introduced
* Plural forms support in resources has been implemented * Plural forms support in resources has been implemented
* Image in image view can be scaled using pinch (Android 2+) * Image in image view can be scaled using pinch (Android 2+)
* Full-screen cover images
===== 1.2.6 (Dec 19, 2011) ===== ===== 1.2.6 (Dec 19, 2011) =====
* Android 3.*, 4.*: bottom buttons are hidden during book reading * Android 3.*, 4.*: bottom buttons are hidden during book reading

View file

@ -238,7 +238,6 @@ public final class FBReader extends ZLAndroidActivity {
); );
final TipsManager manager = TipsManager.Instance(); final TipsManager manager = TipsManager.Instance();
System.err.println("TIPS: " + manager.requiredAction());
switch (manager.requiredAction()) { switch (manager.requiredAction()) {
case Initialize: case Initialize:
startActivity(new Intent(TipsActivity.INITIALIZE_ACTION, null, this, TipsActivity.class)); startActivity(new Intent(TipsActivity.INITIALIZE_ACTION, null, this, TipsActivity.class));

View file

@ -388,21 +388,21 @@ public class BookReader {
beginContentsParagraph(-1); beginContentsParagraph(-1);
} }
public final void addImageReference(String ref) { public final void addImageReference(String ref, boolean isCover) {
addImageReference(ref, (short)0); addImageReference(ref, (short)0, isCover);
} }
public final void addImageReference(String ref, short vOffset) { public final void addImageReference(String ref, short vOffset, boolean isCover) {
final ZLTextWritableModel textModel = myCurrentTextModel; final ZLTextWritableModel textModel = myCurrentTextModel;
if (textModel != null) { if (textModel != null) {
mySectionContainsRegularContents = true; mySectionContainsRegularContents = true;
if (myTextParagraphExists) { if (myTextParagraphExists) {
flushTextBufferToParagraph(); flushTextBufferToParagraph();
textModel.addImage(ref, vOffset); textModel.addImage(ref, vOffset, isCover);
} else { } else {
beginParagraph(ZLTextParagraph.Kind.TEXT_PARAGRAPH); beginParagraph(ZLTextParagraph.Kind.TEXT_PARAGRAPH);
textModel.addControl(FBTextKind.IMAGE, true); textModel.addControl(FBTextKind.IMAGE, true);
textModel.addImage(ref, vOffset); textModel.addImage(ref, vOffset, isCover);
textModel.addControl(FBTextKind.IMAGE, false); textModel.addControl(FBTextKind.IMAGE, false);
endParagraph(); endParagraph();
} }

View file

@ -375,9 +375,11 @@ public final class FB2Reader extends ZLXMLReaderAdapter {
} catch (NumberFormatException e) { } catch (NumberFormatException e) {
} }
imgRef = imgRef.substring(1); imgRef = imgRef.substring(1);
if (!imgRef.equals(myCoverImageReference) || final boolean isCoverImage =
myParagraphsBeforeBodyNumber != myBookReader.Model.BookTextModel.getParagraphsNumber()) { myParagraphsBeforeBodyNumber ==
myBookReader.addImageReference(imgRef, offset); myBookReader.Model.BookTextModel.getParagraphsNumber();
if (!imgRef.equals(myCoverImageReference) || !isCoverImage) {
myBookReader.addImageReference(imgRef, offset, myInsideCoverpage || isCoverImage);
} }
if (myInsideCoverpage) { if (myInsideCoverpage) {
myCoverImageReference = imgRef; myCoverImageReference = imgRef;

View file

@ -53,6 +53,7 @@ class OEBBookReader extends ZLXMLReaderAdapter implements XMLNamespaces {
private String myOPFSchemePrefix; private String myOPFSchemePrefix;
private String myFilePrefix; private String myFilePrefix;
private String myNCXTOCFileName; private String myNCXTOCFileName;
private String myCoverFileName;
OEBBookReader(BookModel model) { OEBBookReader(BookModel model) {
myModelReader = new BookReader(model); myModelReader = new BookReader(model);
@ -86,12 +87,16 @@ class OEBBookReader extends ZLXMLReaderAdapter implements XMLNamespaces {
myModelReader.setMainTextModel(); myModelReader.setMainTextModel();
myModelReader.pushKind(FBTextKind.REGULAR); myModelReader.pushKind(FBTextKind.REGULAR);
int count = 0;
for (String name : myHtmlFileNames) { for (String name : myHtmlFileNames) {
final ZLFile xhtmlFile = ZLFile.createFileByPath(myFilePrefix + name); final ZLFile xhtmlFile = ZLFile.createFileByPath(myFilePrefix + name);
if (xhtmlFile == null) { if (xhtmlFile == null) {
// NPE fix: null for bad attributes in .opf XML file // NPE fix: null for bad attributes in .opf XML file
return false; return false;
} }
if (count++ == 0 && xhtmlFile.getPath().equals(myCoverFileName)) {
continue;
}
final XHTMLReader reader = new XHTMLReader(myModelReader, myFileNumbers); final XHTMLReader reader = new XHTMLReader(myModelReader, myFileNumbers);
final String referenceName = reader.getFileAlias(MiscUtil.archiveEntryName(xhtmlFile.getPath())); final String referenceName = reader.getFileAlias(MiscUtil.archiveEntryName(xhtmlFile.getPath()));
@ -175,6 +180,7 @@ class OEBBookReader extends ZLXMLReaderAdapter implements XMLNamespaces {
private static final String ITEMREF = "itemref"; private static final String ITEMREF = "itemref";
private static final String ITEM = "item"; private static final String ITEM = "item";
private static final String COVER = "cover";
private static final String COVER_IMAGE = "other.ms-coverimage-standard"; private static final String COVER_IMAGE = "other.ms-coverimage-standard";
private static final int READ_NONE = 0; private static final int READ_NONE = 0;
@ -225,12 +231,25 @@ class OEBBookReader extends ZLXMLReaderAdapter implements XMLNamespaces {
if (title != null) { if (title != null) {
myGuideTOC.add(new Reference(title, href)); myGuideTOC.add(new Reference(title, href));
} }
if (type != null && COVER_IMAGE.equals(type)) { if (COVER.equals(type)) {
myModelReader.setMainTextModel();
final ZLFile imageFile = ZLFile.createFileByPath(myFilePrefix + href); final ZLFile imageFile = ZLFile.createFileByPath(myFilePrefix + href);
myCoverFileName = imageFile.getPath();
final String imageName = imageFile.getLongName(); final String imageName = imageFile.getLongName();
myModelReader.addImageReference(imageName, (short)0); final ZLFileImage image = XHTMLImageFinder.getCoverImage(imageFile);
if (image != null) {
myModelReader.setMainTextModel();
myModelReader.addImageReference(imageName, (short)0, true);
myModelReader.addImage(imageName, image);
myModelReader.insertEndOfSectionParagraph();
}
} else if (COVER_IMAGE.equals(type)) {
final ZLFile imageFile = ZLFile.createFileByPath(myFilePrefix + href);
myCoverFileName = imageFile.getPath();
final String imageName = imageFile.getLongName();
myModelReader.setMainTextModel();
myModelReader.addImageReference(imageName, (short)0, true);
myModelReader.addImage(imageName, new ZLFileImage(MimeType.IMAGE_AUTO, imageFile)); myModelReader.addImage(imageName, new ZLFileImage(MimeType.IMAGE_AUTO, imageFile));
myModelReader.insertEndOfSectionParagraph();
} }
} }
} else if (myState == READ_TOUR && SITE == tag) { } else if (myState == READ_TOUR && SITE == tag) {

View file

@ -28,58 +28,15 @@ import org.geometerplus.zlibrary.core.xml.*;
import org.geometerplus.fbreader.formats.util.MiscUtil; import org.geometerplus.fbreader.formats.util.MiscUtil;
class OEBCoverBackgroundReader extends ZLXMLReaderAdapter implements XMLNamespaces { class OEBCoverBackgroundReader extends ZLXMLReaderAdapter implements XMLNamespaces {
private class XHTMLImageFinder extends ZLXMLReaderAdapter {
@Override
public boolean processNamespaces() {
return true;
}
@Override
public boolean startElementHandler(String tag, ZLStringMap attributes) {
tag = tag.toLowerCase();
String href = null;
if ("img".equals(tag)) {
href = attributes.getValue("src");
} else if ("image".equals(tag)) {
href = getAttributeValue(attributes, XLink, "href");
}
if (href != null) {
myImage = new ZLFileImage(
MimeType.IMAGE_AUTO,
ZLFile.createFileByPath(myXHTMLPathPrefix + MiscUtil.decodeHtmlReference(href))
);
return true;
}
return false;
}
}
private ZLFileImage myImage; private ZLFileImage myImage;
private String myPathPrefix; private String myPathPrefix;
private String myXHTMLPathPrefix;
private String myCoverXHTML;
private boolean myReadGuide; private boolean myReadGuide;
public ZLFileImage readCover(ZLFile file) { public ZLFileImage readCover(ZLFile file) {
myPathPrefix = MiscUtil.htmlDirectoryPrefix(file); myPathPrefix = MiscUtil.htmlDirectoryPrefix(file);
myReadGuide = false; myReadGuide = false;
myImage = null; myImage = null;
myCoverXHTML = null;
read(file); read(file);
if (myCoverXHTML != null) {
final ZLFile coverFile = ZLFile.createFileByPath(myCoverXHTML);
if (coverFile != null) {
final String ext = coverFile.getExtension();
if ("gif".equals(ext) || "jpg".equals(ext) || "jpeg".equals(ext)) {
myImage = new ZLFileImage(MimeType.IMAGE_AUTO, coverFile);
} else {
myXHTMLPathPrefix = MiscUtil.htmlDirectoryPrefix(coverFile);
new XHTMLImageFinder().read(coverFile);
}
}
}
return myImage; return myImage;
} }
@ -98,7 +55,9 @@ class OEBCoverBackgroundReader extends ZLXMLReaderAdapter implements XMLNamespac
if (COVER == type) { if (COVER == type) {
final String href = attributes.getValue("href"); final String href = attributes.getValue("href");
if (href != null) { if (href != null) {
myCoverXHTML = myPathPrefix + MiscUtil.decodeHtmlReference(href); final ZLFile coverFile =
ZLFile.createFileByPath(myPathPrefix + MiscUtil.decodeHtmlReference(href));
myImage = XHTMLImageFinder.getCoverImage(coverFile);
return true; return true;
} }
} else if (COVER_IMAGE == type) { } else if (COVER_IMAGE == type) {

View file

@ -0,0 +1,79 @@
/*
* Copyright (C) 2010-2011 Geometer Plus <contact@geometerplus.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
package org.geometerplus.fbreader.formats.oeb;
import org.geometerplus.zlibrary.core.constants.XMLNamespaces;
import org.geometerplus.zlibrary.core.filesystem.ZLFile;
import org.geometerplus.zlibrary.core.image.ZLFileImage;
import org.geometerplus.zlibrary.core.util.MimeType;
import org.geometerplus.zlibrary.core.xml.*;
import org.geometerplus.fbreader.formats.util.MiscUtil;
class XHTMLImageFinder extends ZLXMLReaderAdapter {
static ZLFileImage getCoverImage(ZLFile coverFile) {
if (coverFile == null) {
return null;
}
final String ext = coverFile.getExtension();
if ("gif".equals(ext) || "jpg".equals(ext) || "jpeg".equals(ext)) {
return new ZLFileImage(MimeType.IMAGE_AUTO, coverFile);
} else {
return new XHTMLImageFinder().readImage(coverFile);
}
}
private String myXHTMLPathPrefix;
private ZLFileImage myImage;
ZLFileImage readImage(ZLFile file) {
myXHTMLPathPrefix = MiscUtil.htmlDirectoryPrefix(file);
myImage = null;
read(file);
return myImage;
}
@Override
public boolean processNamespaces() {
return true;
}
@Override
public boolean startElementHandler(String tag, ZLStringMap attributes) {
tag = tag.toLowerCase();
String href = null;
if ("img".equals(tag)) {
href = attributes.getValue("src");
} else if ("image".equals(tag)) {
href = getAttributeValue(attributes, XMLNamespaces.XLink, "href");
}
if (href != null) {
myImage = new ZLFileImage(
MimeType.IMAGE_AUTO,
ZLFile.createFileByPath(myXHTMLPathPrefix + MiscUtil.decodeHtmlReference(href))
);
return true;
}
return false;
}
}

View file

@ -72,10 +72,10 @@ public class MobipocketHtmlBookReader extends HtmlReader {
final int index = Integer.parseInt(recIndex.toString()); final int index = Integer.parseInt(recIndex.toString());
if (paragraphIsOpen()) { if (paragraphIsOpen()) {
endParagraph(); endParagraph();
addImageReference("" + index); addImageReference("" + index, false);
beginParagraph(); beginParagraph();
} else { } else {
addImageReference("" + index); addImageReference("" + index, false);
} }
} catch (NumberFormatException e) { } catch (NumberFormatException e) {
} }

View file

@ -341,7 +341,7 @@ public class PluckerBookReader extends BookReader {
break; break;
case 0x1A: case 0x1A:
safeBeginParagraph(); safeBeginParagraph();
addImageReference(fromNumber(twoBytes(ptr, cur + 1)), (short) 0); addImageReference(fromNumber(twoBytes(ptr, cur + 1)), (short)0, false);
break; break;
case 0x22: case 0x22:
if (!myParagraphStarted) { if (!myParagraphStarted) {
@ -380,7 +380,7 @@ public class PluckerBookReader extends BookReader {
case 0x53: // color setting is ignored case 0x53: // color setting is ignored
break; break;
case 0x5C: case 0x5C:
addImageReference(fromNumber(twoBytes(ptr, cur + 3)), (short) 0); addImageReference(fromNumber(twoBytes(ptr, cur + 3)), (short)0, false);
break; break;
case 0x60: // underlined text is ignored case 0x60: // underlined text is ignored
break; break;

View file

@ -48,7 +48,7 @@ class XHTMLTagImageAction extends XHTMLTagAction {
modelReader.endParagraph(); modelReader.endParagraph();
} }
final String imageName = imageFile.getLongName(); final String imageName = imageFile.getLongName();
modelReader.addImageReference(imageName, (short)0); modelReader.addImageReference(imageName, (short)0, false);
modelReader.addImage(imageName, new ZLFileImage(MimeType.IMAGE_AUTO, imageFile)); modelReader.addImage(imageName, new ZLFileImage(MimeType.IMAGE_AUTO, imageFile));
if (flag) { if (flag) {
modelReader.beginParagraph(); modelReader.beginParagraph();

View file

@ -29,82 +29,104 @@ final class DummyPaintContext extends ZLPaintContext {
DummyPaintContext() { DummyPaintContext() {
} }
@Override
public void clear(ZLFile wallpaperFile, boolean doMirror) { public void clear(ZLFile wallpaperFile, boolean doMirror) {
} }
@Override
public void clear(ZLColor color) { public void clear(ZLColor color) {
} }
@Override
public ZLColor getBackgroundColor() { public ZLColor getBackgroundColor() {
return new ZLColor(0, 0, 0); return new ZLColor(0, 0, 0);
} }
@Override
protected void setFontInternal(String family, int size, boolean bold, boolean italic, boolean underline) { protected void setFontInternal(String family, int size, boolean bold, boolean italic, boolean underline) {
} }
@Override
public void setTextColor(ZLColor color) { public void setTextColor(ZLColor color) {
} }
@Override
public void setLineColor(ZLColor color, int style) { public void setLineColor(ZLColor color, int style) {
} }
@Override
public void setLineWidth(int width) { public void setLineWidth(int width) {
} }
@Override
public void setFillColor(ZLColor color, int alpha, int style) { public void setFillColor(ZLColor color, int alpha, int style) {
} }
@Override
public int getWidth() { public int getWidth() {
return 1; return 1;
} }
@Override
public int getHeight() { public int getHeight() {
return 1; return 1;
} }
@Override
public int getStringWidth(char[] string, int offset, int length) { public int getStringWidth(char[] string, int offset, int length) {
return 1; return 1;
} }
@Override
protected int getSpaceWidthInternal() { protected int getSpaceWidthInternal() {
return 1; return 1;
} }
@Override
protected int getStringHeightInternal() { protected int getStringHeightInternal() {
return 1; return 1;
} }
@Override
protected int getDescentInternal() { protected int getDescentInternal() {
return 1; return 1;
} }
@Override
public void drawString(int x, int y, char[] string, int offset, int length) { public void drawString(int x, int y, char[] string, int offset, int length) {
} }
public int imageWidth(ZLImageData image) { @Override
return 1; public Size imageSize(ZLImageData image, Size maxSize, ScalingType scaling) {
return null;
} }
public int imageHeight(ZLImageData image) { @Override
return 1; public void drawImage(int x, int y, ZLImageData image, Size maxSize, ScalingType scaling) {
}
public void drawImage(int x, int y, ZLImageData image) {
} }
@Override
public void drawLine(int x0, int y0, int x1, int y1) { public void drawLine(int x0, int y0, int x1, int y1) {
} }
@Override
public void fillRectangle(int x0, int y0, int x1, int y1) { public void fillRectangle(int x0, int y0, int x1, int y1) {
} }
@Override
public void drawFilledCircle(int x, int y, int r) { public void drawFilledCircle(int x, int y, int r) {
} }
@Override
public void fillPolygon(int[] xs, int ys[]) { public void fillPolygon(int[] xs, int ys[]) {
} }
@Override
public void drawPolygonalLine(int[] xs, int ys[]) { public void drawPolygonalLine(int[] xs, int ys[]) {
} }
@Override
public void drawOutline(int[] xs, int ys[]) { public void drawOutline(int[] xs, int ys[]) {
} }
@Override
public String realFontFamilyName(String fontFamily) { public String realFontFamilyName(String fontFamily) {
return fontFamily; return fontFamily;
} }
@Override
protected void fillFamiliesList(ArrayList<String> families) { protected void fillFamiliesList(ArrayList<String> families) {
} }
} }

View file

@ -145,9 +145,35 @@ abstract public class ZLPaintContext {
} }
abstract public void drawString(int x, int y, char[] string, int offset, int length); abstract public void drawString(int x, int y, char[] string, int offset, int length);
abstract public int imageWidth(ZLImageData image); public static final class Size {
abstract public int imageHeight(ZLImageData image); public final int Width;
abstract public void drawImage(int x, int y, ZLImageData image); public final int Height;
public Size(int w, int h) {
Width = w;
Height = h;
}
@Override
public boolean equals(Object other) {
if (other == this) {
return true;
}
if (!(other instanceof Size)) {
return false;
}
final Size s = (Size)other;
return Width == s.Width && Height == s.Height;
}
}
public static enum ScalingType {
OriginalSize,
IntegerCoefficient,
FitMaximum
}
abstract public Size imageSize(ZLImageData image, Size maxSize, ScalingType scaling);
abstract public void drawImage(int x, int y, ZLImageData image, Size maxSize, ScalingType scaling);
abstract public void drawLine(int x0, int y0, int x1, int y1); abstract public void drawLine(int x0, int y0, int x1, int y1);
abstract public void fillRectangle(int x0, int y0, int x1, int y1); abstract public void fillRectangle(int x0, int y0, int x1, int y1);

View file

@ -26,11 +26,13 @@ public final class ZLImageEntry {
private final ZLImageMap myImageMap; private final ZLImageMap myImageMap;
public final String Id; public final String Id;
public final short VOffset; public final short VOffset;
public final boolean IsCover;
ZLImageEntry(ZLImageMap imageMap, String id, short vOffset) { ZLImageEntry(ZLImageMap imageMap, String id, short vOffset, boolean isCover) {
myImageMap = imageMap; myImageMap = imageMap;
Id = id; Id = id;
VOffset = vOffset; VOffset = vOffset;
IsCover = isCover;
} }
public ZLImage getImage() { public ZLImage getImage() {

View file

@ -162,7 +162,8 @@ public class ZLTextPlainModel implements ZLTextModel {
final short len = (short)data[dataOffset++]; final short len = (short)data[dataOffset++];
final String id = new String(data, dataOffset, len); final String id = new String(data, dataOffset, len);
dataOffset += len; dataOffset += len;
myImageEntry = new ZLImageEntry(myImageMap, id, vOffset); final boolean isCover = data[dataOffset++] != 0;
myImageEntry = new ZLImageEntry(myImageMap, id, vOffset, isCover);
break; break;
} }
case ZLTextParagraph.Entry.FIXED_HSPACE: case ZLTextParagraph.Entry.FIXED_HSPACE:

View file

@ -28,7 +28,7 @@ public interface ZLTextWritableModel extends ZLTextModel {
//void addControl(ZLTextForcedControlEntry entry); //void addControl(ZLTextForcedControlEntry entry);
void addHyperlinkControl(byte textKind, byte hyperlinkType, String id); void addHyperlinkControl(byte textKind, byte hyperlinkType, String id);
void addImage(String id, short vOffset); void addImage(String id, short vOffset, boolean isCover);
void addFixedHSpace(short length); void addFixedHSpace(short length);
void stopReading(); void stopReading();

View file

@ -129,16 +129,18 @@ public final class ZLTextWritablePlainModel extends ZLTextPlainModel implements
myBlockOffset = blockOffset + labelLength; myBlockOffset = blockOffset + labelLength;
} }
public void addImage(String id, short vOffset) { public void addImage(String id, short vOffset, boolean isCover) {
final int len = id.length(); final int len = id.length();
final char[] block = getDataBlock(3 + len); final char[] block = getDataBlock(4 + len);
++myParagraphLengths[myParagraphsNumber - 1]; ++myParagraphLengths[myParagraphsNumber - 1];
int blockOffset = myBlockOffset; int blockOffset = myBlockOffset;
block[blockOffset++] = (char)ZLTextParagraph.Entry.IMAGE; block[blockOffset++] = (char)ZLTextParagraph.Entry.IMAGE;
block[blockOffset++] = (char)vOffset; block[blockOffset++] = (char)vOffset;
block[blockOffset++] = (char)len; block[blockOffset++] = (char)len;
id.getChars(0, len, block, blockOffset); id.getChars(0, len, block, blockOffset);
myBlockOffset = blockOffset + len; blockOffset += len;
block[blockOffset++] = (char)(isCover ? 1 : 0);
myBlockOffset = blockOffset;
} }
public void addFixedHSpace(short length) { public void addFixedHSpace(short length) {

View file

@ -25,10 +25,12 @@ public final class ZLTextImageElement extends ZLTextElement {
public final String Id; public final String Id;
public final ZLImageData ImageData; public final ZLImageData ImageData;
public final String URI; public final String URI;
public final boolean IsCover;
ZLTextImageElement(String id, ZLImageData imageData, String uri) { ZLTextImageElement(String id, ZLImageData imageData, String uri, boolean isCover) {
Id = id; Id = id;
ImageData = imageData; ImageData = imageData;
URI = uri; URI = uri;
IsCover = isCover;
} }
} }

View file

@ -95,7 +95,7 @@ public final class ZLTextParagraphCursor {
if (hyperlink != null) { if (hyperlink != null) {
hyperlink.addElementIndex(elements.size()); hyperlink.addElementIndex(elements.size());
} }
elements.add(new ZLTextImageElement(imageEntry.Id, data, image.getURI())); elements.add(new ZLTextImageElement(imageEntry.Id, data, image.getURI(), imageEntry.IsCover));
} }
} }
break; break;

View file

@ -779,7 +779,15 @@ public abstract class ZLTextView extends ZLTextViewBase {
? getSelectedForegroundColor() : getTextColor(getTextStyle().Hyperlink) ? getSelectedForegroundColor() : getTextColor(getTextStyle().Hyperlink)
); );
} else if (element instanceof ZLTextImageElement) { } else if (element instanceof ZLTextImageElement) {
context.drawImage(areaX, areaY, ((ZLTextImageElement)element).ImageData); final ZLTextImageElement imageElement = (ZLTextImageElement)element;
context.drawImage(
areaX, areaY,
imageElement.ImageData,
getTextAreaSize(),
imageElement.IsCover
? ZLPaintContext.ScalingType.FitMaximum
: ZLPaintContext.ScalingType.IntegerCoefficient
);
} else if (element == ZLTextElement.HSpace) { } else if (element == ZLTextElement.HSpace) {
final int cw = context.getSpaceWidth(); final int cw = context.getSpaceWidth();
/* /*

View file

@ -57,6 +57,10 @@ abstract class ZLTextViewBase extends ZLView {
public abstract ZLColor getTextColor(ZLTextHyperlink hyperlink); public abstract ZLColor getTextColor(ZLTextHyperlink hyperlink);
public abstract ZLColor getHighlightingColor(); public abstract ZLColor getHighlightingColor();
ZLPaintContext.Size getTextAreaSize() {
return new ZLPaintContext.Size(getTextAreaWidth(), getTextAreaHeight());
}
int getTextAreaHeight() { int getTextAreaHeight() {
return myContext.getHeight() - getTopMargin() - getBottomMargin(); return myContext.getHeight() - getTopMargin() - getBottomMargin();
} }
@ -116,7 +120,15 @@ abstract class ZLTextViewBase extends ZLView {
if (element instanceof ZLTextWord) { if (element instanceof ZLTextWord) {
return getWordWidth((ZLTextWord)element, charIndex); return getWordWidth((ZLTextWord)element, charIndex);
} else if (element instanceof ZLTextImageElement) { } else if (element instanceof ZLTextImageElement) {
return myContext.imageWidth(((ZLTextImageElement)element).ImageData); final ZLTextImageElement imageElement = (ZLTextImageElement)element;
final ZLPaintContext.Size size = myContext.imageSize(
imageElement.ImageData,
getTextAreaSize(),
imageElement.IsCover
? ZLPaintContext.ScalingType.FitMaximum
: ZLPaintContext.ScalingType.IntegerCoefficient
);
return size != null ? size.Width : 0;
} else if (element == ZLTextElement.IndentElement) { } else if (element == ZLTextElement.IndentElement) {
return myTextStyle.getFirstLineIndentDelta(); return myTextStyle.getFirstLineIndentDelta();
} else if (element instanceof ZLTextFixedHSpaceElement) { } else if (element instanceof ZLTextFixedHSpaceElement) {
@ -129,7 +141,15 @@ abstract class ZLTextViewBase extends ZLView {
if (element instanceof ZLTextWord) { if (element instanceof ZLTextWord) {
return getWordHeight(); return getWordHeight();
} else if (element instanceof ZLTextImageElement) { } else if (element instanceof ZLTextImageElement) {
return myContext.imageHeight(((ZLTextImageElement)element).ImageData) + final ZLTextImageElement imageElement = (ZLTextImageElement)element;
final ZLPaintContext.Size size = myContext.imageSize(
imageElement.ImageData,
getTextAreaSize(),
imageElement.IsCover
? ZLPaintContext.ScalingType.FitMaximum
: ZLPaintContext.ScalingType.IntegerCoefficient
);
return (size != null ? size.Height : 0) +
Math.max(myContext.getStringHeight() * (myTextStyle.getLineSpacePercent() - 100) / 100, 3); Math.max(myContext.getStringHeight() * (myTextStyle.getLineSpacePercent() - 100) / 100, 3);
} }
return 0; return 0;

View file

@ -23,13 +23,14 @@ import android.graphics.Bitmap;
import android.graphics.BitmapFactory; import android.graphics.BitmapFactory;
import org.geometerplus.zlibrary.core.image.ZLImageData; import org.geometerplus.zlibrary.core.image.ZLImageData;
import org.geometerplus.zlibrary.core.view.ZLPaintContext;
public abstract class ZLAndroidImageData implements ZLImageData { public abstract class ZLAndroidImageData implements ZLImageData {
private Bitmap myBitmap; private Bitmap myBitmap;
private int myRealWidth; private int myRealWidth;
private int myRealHeight; private int myRealHeight;
private int myLastRequestedWidth = -1; private ZLPaintContext.Size myLastRequestedSize = null;
private int myLastRequestedHeight = -1; private ZLPaintContext.ScalingType myLastRequestedScaling = ZLPaintContext.ScalingType.OriginalSize;
protected ZLAndroidImageData() { protected ZLAndroidImageData() {
} }
@ -37,18 +38,23 @@ public abstract class ZLAndroidImageData implements ZLImageData {
protected abstract Bitmap decodeWithOptions(BitmapFactory.Options options); protected abstract Bitmap decodeWithOptions(BitmapFactory.Options options);
public Bitmap getFullSizeBitmap() { public Bitmap getFullSizeBitmap() {
return getBitmap(0, 0, true); return getBitmap(null, ZLPaintContext.ScalingType.OriginalSize);
} }
public Bitmap getBitmap(int maxWidth, int maxHeight) { public Bitmap getBitmap(int maxWidth, int maxHeight) {
return getBitmap(maxWidth, maxHeight, false); return getBitmap(new ZLPaintContext.Size(maxWidth, maxHeight), ZLPaintContext.ScalingType.FitMaximum);
} }
private synchronized Bitmap getBitmap(int maxWidth, int maxHeight, boolean ignoreSize) { public Bitmap getBitmap(ZLPaintContext.Size maxSize, ZLPaintContext.ScalingType scaling) {
if (!ignoreSize && (maxWidth <= 0 || maxHeight <= 0)) { if (scaling != ZLPaintContext.ScalingType.OriginalSize) {
return null; if (maxSize == null || maxSize.Width <= 0 || maxSize.Height <= 0) {
return null;
}
} }
if (maxWidth != myLastRequestedWidth || maxHeight != myLastRequestedHeight) { if (maxSize == null) {
maxSize = new ZLPaintContext.Size(-1, -1);
}
if (!maxSize.equals(myLastRequestedSize) || scaling != myLastRequestedScaling) {
if (myBitmap != null) { if (myBitmap != null) {
myBitmap.recycle(); myBitmap.recycle();
myBitmap = null; myBitmap = null;
@ -63,34 +69,67 @@ public abstract class ZLAndroidImageData implements ZLImageData {
} }
options.inJustDecodeBounds = false; options.inJustDecodeBounds = false;
int coefficient = 1; int coefficient = 1;
if (!ignoreSize) { if (scaling == ZLPaintContext.ScalingType.IntegerCoefficient) {
if (myRealHeight > maxHeight || myRealWidth > maxWidth) { if (myRealHeight > maxSize.Height || myRealWidth > maxSize.Width) {
coefficient = 1 + Math.max( coefficient = 1 + Math.max(
(myRealHeight - 1) / maxHeight, (myRealHeight - 1) / maxSize.Height,
(myRealWidth - 1) / maxWidth (myRealWidth - 1) / maxSize.Width
); );
} }
} }
options.inSampleSize = coefficient; options.inSampleSize = coefficient;
myBitmap = decodeWithOptions(options); myBitmap = decodeWithOptions(options);
if (myBitmap != null) { if (myBitmap != null) {
if (!ignoreSize) { switch (scaling) {
final int bWidth = myBitmap.getWidth(); case OriginalSize:
final int bHeight = myBitmap.getHeight(); break;
if (bWidth > 0 && bHeight > 0 && (bWidth > maxWidth || bHeight > maxHeight)) { case FitMaximum:
final int w, h; {
if (bWidth * maxHeight > bHeight * maxWidth) { final int bWidth = myBitmap.getWidth();
w = maxWidth; final int bHeight = myBitmap.getHeight();
h = Math.max(1, bHeight * maxWidth / bWidth); if (bWidth > 0 && bHeight > 0 &&
} else { bWidth != maxSize.Width && bHeight != maxSize.Height) {
h = maxHeight; final int w, h;
w = Math.max(1, bWidth * maxHeight / bHeight); if (bWidth * maxSize.Height > bHeight * maxSize.Width) {
w = maxSize.Width;
h = Math.max(1, bHeight * w / bWidth);
} else {
h = maxSize.Height;
w = Math.max(1, bWidth * h / bHeight);
}
final Bitmap scaled =
Bitmap.createScaledBitmap(myBitmap, w, h, false);
if (scaled != null) {
myBitmap = scaled;
}
} }
myBitmap = Bitmap.createScaledBitmap(myBitmap, w, h, false); break;
}
case IntegerCoefficient:
{
final int bWidth = myBitmap.getWidth();
final int bHeight = myBitmap.getHeight();
if (bWidth > 0 && bHeight > 0 &&
(bWidth > maxSize.Width || bHeight > maxSize.Height)) {
final int w, h;
if (bWidth * maxSize.Height > bHeight * maxSize.Width) {
w = maxSize.Width;
h = Math.max(1, bHeight * w / bWidth);
} else {
h = maxSize.Height;
w = Math.max(1, bWidth * h / bHeight);
}
final Bitmap scaled =
Bitmap.createScaledBitmap(myBitmap, w, h, false);
if (scaled != null) {
myBitmap = scaled;
}
}
break;
} }
} }
myLastRequestedWidth = maxWidth; myLastRequestedSize = maxSize;
myLastRequestedHeight = maxHeight; myLastRequestedScaling = scaling;
} }
} catch (OutOfMemoryError e) { } catch (OutOfMemoryError e) {
e.printStackTrace(); e.printStackTrace();

View file

@ -244,6 +244,7 @@ public final class ZLAndroidPaintContext extends ZLPaintContext {
return myHeight; return myHeight;
} }
@Override
public int getStringWidth(char[] string, int offset, int length) { public int getStringWidth(char[] string, int offset, int length) {
boolean containsSoftHyphen = false; boolean containsSoftHyphen = false;
for (int i = offset; i < offset + length; ++i) { for (int i = offset; i < offset + length; ++i) {
@ -266,15 +267,19 @@ public final class ZLAndroidPaintContext extends ZLPaintContext {
return (int)(myTextPaint.measureText(corrected, 0, len) + 0.5f); return (int)(myTextPaint.measureText(corrected, 0, len) + 0.5f);
} }
} }
@Override
protected int getSpaceWidthInternal() { protected int getSpaceWidthInternal() {
return (int)(myTextPaint.measureText(" ", 0, 1) + 0.5f); return (int)(myTextPaint.measureText(" ", 0, 1) + 0.5f);
} }
@Override
protected int getStringHeightInternal() { protected int getStringHeightInternal() {
return (int)(myTextPaint.getTextSize() + 0.5f); return (int)(myTextPaint.getTextSize() + 0.5f);
} }
@Override
protected int getDescentInternal() { protected int getDescentInternal() {
return (int)(myTextPaint.descent() + 0.5f); return (int)(myTextPaint.descent() + 0.5f);
} }
@Override
public void drawString(int x, int y, char[] string, int offset, int length) { public void drawString(int x, int y, char[] string, int offset, int length) {
boolean containsSoftHyphen = false; boolean containsSoftHyphen = false;
for (int i = offset; i < offset + length; ++i) { for (int i = offset; i < offset + length; ++i) {
@ -298,23 +303,22 @@ public final class ZLAndroidPaintContext extends ZLPaintContext {
} }
} }
public int imageWidth(ZLImageData imageData) { @Override
Bitmap bitmap = ((ZLAndroidImageData)imageData).getBitmap(myWidth, myHeight); public Size imageSize(ZLImageData imageData, Size maxSize, ScalingType scaling) {
return ((bitmap != null) && !bitmap.isRecycled()) ? bitmap.getWidth() : 0; final Bitmap bitmap = ((ZLAndroidImageData)imageData).getBitmap(maxSize, scaling);
return (bitmap != null && !bitmap.isRecycled())
? new Size(bitmap.getWidth(), bitmap.getHeight()) : null;
} }
public int imageHeight(ZLImageData imageData) { @Override
Bitmap bitmap = ((ZLAndroidImageData)imageData).getBitmap(myWidth, myHeight); public void drawImage(int x, int y, ZLImageData imageData, Size maxSize, ScalingType scaling) {
return ((bitmap != null) && !bitmap.isRecycled()) ? bitmap.getHeight() : 0; final Bitmap bitmap = ((ZLAndroidImageData)imageData).getBitmap(maxSize, scaling);
} if (bitmap != null && !bitmap.isRecycled()) {
public void drawImage(int x, int y, ZLImageData imageData) {
Bitmap bitmap = ((ZLAndroidImageData)imageData).getBitmap(myWidth, myHeight);
if ((bitmap != null) && !bitmap.isRecycled()) {
myCanvas.drawBitmap(bitmap, x, y - bitmap.getHeight(), myFillPaint); myCanvas.drawBitmap(bitmap, x, y - bitmap.getHeight(), myFillPaint);
} }
} }
@Override
public void drawLine(int x0, int y0, int x1, int y1) { public void drawLine(int x0, int y0, int x1, int y1) {
final Canvas canvas = myCanvas; final Canvas canvas = myCanvas;
final Paint paint = myLinePaint; final Paint paint = myLinePaint;
@ -325,6 +329,7 @@ public final class ZLAndroidPaintContext extends ZLPaintContext {
paint.setAntiAlias(true); paint.setAntiAlias(true);
} }
@Override
public void fillRectangle(int x0, int y0, int x1, int y1) { public void fillRectangle(int x0, int y0, int x1, int y1) {
if (x1 < x0) { if (x1 < x0) {
int swap = x1; int swap = x1;
@ -338,14 +343,17 @@ public final class ZLAndroidPaintContext extends ZLPaintContext {
} }
myCanvas.drawRect(x0, y0, x1 + 1, y1 + 1, myFillPaint); myCanvas.drawRect(x0, y0, x1 + 1, y1 + 1, myFillPaint);
} }
@Override
public void drawFilledCircle(int x, int y, int r) { public void drawFilledCircle(int x, int y, int r) {
// TODO: implement // TODO: implement
} }
@Override
public String realFontFamilyName(String fontFamily) { public String realFontFamilyName(String fontFamily) {
return AndroidFontUtil.realFontFamilyName(fontFamily); return AndroidFontUtil.realFontFamilyName(fontFamily);
} }
@Override
protected void fillFamiliesList(ArrayList<String> families) { protected void fillFamiliesList(ArrayList<String> families) {
AndroidFontUtil.fillFamiliesList(families, false); AndroidFontUtil.fillFamiliesList(families, false);
} }