Esempio n. 1
0
	point TextBox::reflowText(LayoutEngine& eng, const Dimensions& containing, const point& current_cursor)
	{
		// clear old data so we can re-calculate it.
		// XXX Future note.
		// unless the text has changed or the width of the containing box changes we shouldn't
		// have to recalculate this.
		lines_.clear();

		point cursor = current_cursor;

		FixedPoint y1 = cursor.y + getOffset().y;
		// XXX if padding left/border left applies should reduce width and move cursor position if isFirstInlineChild() is set.
		// Simlarly the last line width should be reduced by padding right/border right.
		FixedPoint width = eng.getWidthAtPosition(y1, y1 + getLineHeight(), containing.content_.width) - cursor.x + eng.getXAtPosition(y1, y1 + getLineHeight());

		Text::iterator last_it = txt_->begin();
		Text::iterator it = last_it;

		bool done = false;
		while(it != txt_->end()) {
			LinePtr line = txt_->reflowText(it, width, getStyleNode());
			if(line != nullptr && !line->line.empty()) {
				// is the line larger than available space and are there floats present?
				FixedPoint last_x = line->line.back().advance.back().x;
				if(last_x > width && eng.hasFloatsAtPosition(y1, y1 + getLineHeight())) {
					cursor.y += getLineHeight();
					y1 = cursor.y + getOffset().y;
					cursor.x = eng.getXAtPosition(y1, y1 + getLineHeight());
					it = last_it;
					width = eng.getWidthAtPosition(y1, y1 + getLineHeight(), containing.content_.width);
					continue;
				}

				lines_.emplace_back(line, cursor);
				lines_.back().width_ = calculateWidth(lines_.back());
				// XXX This height needs to be modified later if we have inline elements with a different lineheight
				lines_.back().height_ = getLineHeight();
				cursor.x += lines_.back().width_;

				if(line->is_end_line) {
					// update the cursor for the next line
					cursor.y += getLineHeight();
					y1 = cursor.y + getOffset().y;
					cursor.x = eng.getXAtPosition(y1, y1 + getLineHeight());
				}
			}					
		}

		int max_w = 0;
		for(auto& line : lines_) {
			max_w = std::max(max_w, line.width_);
		}
		setContentWidth(max_w);
		
		if(!lines_.empty()) {
			setContentHeight(lines_.back().offset_.y + getLineHeight());
		}

		return cursor;
	}
Esempio n. 2
0
int main(int argc, char *argv[])
{
    le_int32 failures = 0;

    for (le_int32 test = 0; test < testCount; test += 1) {
        LEErrorCode fontStatus = LE_NO_ERROR;

        printf("Test %d, font = %s... ", test, testInputs[test].fontName);

        PortableFontInstance fontInstance(testInputs[test].fontName, 12, fontStatus);

        if (LE_FAILURE(fontStatus)) {
            printf("could not open font.\n");
            continue;
        }

        LEErrorCode success = LE_NO_ERROR;
        LayoutEngine *engine = LayoutEngine::layoutEngineFactory(&fontInstance, testInputs[test].scriptCode, -1, success);
        le_int32 textLength = testInputs[test].textLength;
        le_bool result;
        TestResult actual;

        if (LE_FAILURE(success)) {
            // would be nice to print the script name here, but
            // don't want to maintain a table, and don't want to
            // require ICU just for the script name...
            printf("could not create a LayoutEngine.\n");
            continue;
        }

        actual.glyphCount = engine->layoutChars(testInputs[test].text, 0, textLength, textLength, testInputs[test].rightToLeft, 0, 0, success);

        actual.glyphs    = new LEGlyphID[actual.glyphCount];
        actual.indices   = new le_int32[actual.glyphCount];
        actual.positions = new float[actual.glyphCount * 2 + 2];

        engine->getGlyphs(actual.glyphs, success);
        engine->getCharIndices(actual.indices, success);
        engine->getGlyphPositions(actual.positions, success);

        result = compareResults(test, &testResults[test], &actual);

        if (result) {
            printf("passed.\n");
        } else {
            failures += 1;
            printf("failed.\n");
        }

        delete[] actual.positions;
        delete[] actual.indices;
        delete[] actual.glyphs;
        delete   engine;
    }

    return failures;
}
Esempio n. 3
0
	void TextBox::handleLayout(LayoutEngine& eng, const Dimensions& containing)
	{
		// TextBox's have no children to deal with, by definition.	
		// XXX fix the point() to be the actual last point, say from LayoutEngine
		point cursor = reflowText(eng, containing, eng.getCursor());
		eng.setCursor(cursor);

		calculateHorzMPB(containing.content_.width);
		calculateVertMPB(containing.content_.height);
	}
Esempio n. 4
0
/*
 * Class:     sun_font_SunLayoutEngine
 * Method:    nativeLayout
 * Signature: (Lsun/font/FontStrike;[CIIIIZLjava/awt/geom/Point2D$Float;Lsun/font/GlyphLayout$GVData;)V
 */
JNIEXPORT void JNICALL Java_sun_font_SunLayoutEngine_nativeLayout
   (JNIEnv *env, jclass cls, jobject font2d, jobject strike, jfloatArray matrix, jint gmask,
   jint baseIndex, jcharArray text, jint start, jint limit, jint min, jint max,
   jint script, jint lang, jint typo_flags, jobject pt, jobject gvdata,
   jlong upem, jlong layoutTables)
{
    //  fprintf(stderr, "nl font: %x strike: %x script: %d\n", font2d, strike, script); fflush(stderr);
  float mat[4];
  env->GetFloatArrayRegion(matrix, 0, 4, mat);
  FontInstanceAdapter fia(env, font2d, strike, mat, 72, 72, (le_int32) upem, (TTLayoutTableCache *) layoutTables);
  LEErrorCode success = LE_NO_ERROR;
  LayoutEngine *engine = LayoutEngine::layoutEngineFactory(&fia, script, lang, typo_flags & TYPO_MASK, success);

  if (min < 0) min = 0; if (max < min) max = min; /* defensive coding */
  // have to copy, yuck, since code does upcalls now.  this will be soooo slow
  jint len = max - min;
  jchar buffer[256];
  jchar* chars = buffer;
  if (len > 256) {
    size_t size = len * sizeof(jchar);
    if (size / sizeof(jchar) != len) {
      return;
    }
    chars = (jchar*)malloc(size);
    if (chars == 0) {
      return;
    }
  }
  //  fprintf(stderr, "nl chars: %x text: %x min %d len %d typo %x\n", chars, text, min, len, typo_flags); fflush(stderr);

  env->GetCharArrayRegion(text, min, len, chars);

  jfloat x, y;
  getFloat(env, pt, x, y);
  jboolean rtl = (typo_flags & TYPO_RTL) != 0;
  int glyphCount = engine->layoutChars(chars, start - min, limit - start, len, rtl, x, y, success);
  //   fprintf(stderr, "sle nl len %d -> gc: %d\n", len, glyphCount); fflush(stderr);

  engine->getGlyphPosition(glyphCount, x, y, success);

  //  fprintf(stderr, "layout glyphs: %d x: %g y: %g\n", glyphCount, x, y); fflush(stderr);

  if (putGV(env, gmask, baseIndex, gvdata, engine, glyphCount)) {
    // !!! hmmm, could use current value in positions array of GVData...
    putFloat(env, pt, x, y);
  }

  if (chars != buffer) {
    free(chars);
  }

  delete engine;

}
	void InlineBlockBox::handlePreChildLayout2(LayoutEngine& eng, const Dimensions& containing)
	{
		cursor_ = eng.getCursor();
		eng.setCursor(point(0, 0));
		if(!getChildren().empty() || !isReplaceable()) {
			setContentHeight(0);
		} else if(isReplaceable()) {
			NodePtr node = getNode();
			const rect& r = node->getDimensions();
			setContentWidth(r.w() * LayoutEngine::getFixedPointScale());
			setContentHeight(r.h() * LayoutEngine::getFixedPointScale());
		}
	}
Esempio n. 6
0
	RootBoxPtr Box::createLayout(StyleNodePtr node, int containing_width, int containing_height)
	{
		LayoutEngine e;
		// search for the body element then render that content.
		node->preOrderTraversal([&e, containing_width, containing_height](StyleNodePtr node){
			auto n = node->getNode();
			if(n->id() == NodeId::ELEMENT && n->hasTag(ElementId::HTML)) {
				e.layoutRoot(node, nullptr, point(containing_width * LayoutEngine::getFixedPointScale(), containing_height * LayoutEngine::getFixedPointScale()));
				return false;
			}
			return true;
		});
		node->getNode()->layoutComplete();

		auto root_box = e.getRoot();
		root_box->setLayoutDimensions(containing_width, containing_height);
		return root_box;
	}
Esempio n. 7
0
	void BlockBox::handleLayout(LayoutEngine& eng, const Dimensions& containing)
	{
		if(isReplaceable()) {
			layoutChildren(eng);
		} else {
			layoutChildren(eng);
			layoutHeight(containing);
		}

		if(isFloat()) {
			FixedPoint top = 0;
			const FixedPoint lh = getStyleNode()->getHeight()->isAuto() ? getLineHeight() : getStyleNode()->getHeight()->getLength().compute(containing.content_.height);
			const FixedPoint box_w = getDimensions().content_.width;

			FixedPoint y = 0;
			FixedPoint x = 0;

			FixedPoint y1 = y + getOffset().y;
			FixedPoint left = getStyleNode()->getFloat() == Float::LEFT ? eng.getXAtPosition(y1, y1 + lh) + x : eng.getX2AtPosition(y1, y1 + lh);
			FixedPoint w = eng.getWidthAtPosition(y1, y1 + lh, containing.content_.width);
			bool placed = false;
			while(!placed) {
				if(w >= box_w) {
					left = left - (getStyleNode()->getFloat() == Float::LEFT ? x : box_w) + getMBPLeft();
					top = y + getMBPTop() + containing.content_.height;
					placed = true;
				} else {
					y += lh;
					y1 = y + getOffset().y;
					left = getStyleNode()->getFloat() == Float::LEFT ? eng.getXAtPosition(y1, y1 + lh) + x : eng.getX2AtPosition(y1, y1 + lh);
					w = eng.getWidthAtPosition(y1, y1 + lh, containing.content_.width);
				}
			}
			setContentX(left);
			setContentY(top);

		} else {
			for(auto& child : getChildren()) {
				setContentHeight(child->getTop() + child->getHeight() + child->getMBPBottom());
			}
		}
	}
Esempio n. 8
0
	void Box::layout(LayoutEngine& eng, const Dimensions& ocontaining)
	{
		auto containing = ocontaining;
		auto styles = getStyleNode();

		std::unique_ptr<LayoutEngine::FloatContextManager> fcm;
		if(getParent() && getParent()->isFloat()) {
			fcm.reset(new LayoutEngine::FloatContextManager(eng, FloatList()));
		}

		point cursor;
		// If we have a clear flag set, then move the cursor in the layout engine to clear appropriate floats.
		if(node_ != nullptr) {
			eng.moveCursorToClearFloats(node_->getClear(), cursor);
		}

		NodePtr node = getNode();

		std::unique_ptr<RenderContext::Manager> ctx_manager;
		if(node != nullptr) {
			ctx_manager.reset(new RenderContext::Manager(node->getProperties()));
		}

		if(styles != nullptr) {
			auto ovf = styles->getOverflow();
			// this is kind of a hack, since we really want to avoid re-running layout
			//if(ovf == Overflow::SCROLL || ovf == Overflow::AUTO) {
				containing.content_.width -= scrollbar_default_width * LayoutEngine::getFixedPointScale();
			//}
		}

		handlePreChildLayout(eng, containing);

		if(node_ != nullptr) {
			const std::vector<StyleNodePtr>& node_children = node_->getChildren();
			if(!node_children.empty()) {
				boxes_ = eng.layoutChildren(node_children, shared_from_this());
			}
		}

		for(auto& child : boxes_) {
			if(child->isFloat()) {
				handlePreChildLayout3(eng, containing);
				child->layout(eng, dimensions_);
				handlePostFloatChildLayout(eng, child);
				eng.addFloat(child);
			}
		}

		offset_ = (getParent() != nullptr ? getParent()->getOffset() : point()) + point(dimensions_.content_.x, dimensions_.content_.y);
		if(isBlockBox()) {
			const FixedPoint y1 = offset_.y;
			point p(eng.getXAtPosition(y1, y1 + getLineHeight()), 0);
			eng.setCursor(p);
		}

		handlePreChildLayout2(eng, containing);

		for(auto& child : boxes_) {
			if(!child->isFloat()) {
				handlePreChildLayout3(eng, containing);
				child->layout(eng, dimensions_);
				handlePostChildLayout(eng, child);
			}
		}
		
		handleLayout(eng, containing);
		//layoutAbsolute(eng, containing);

		for(auto& child : boxes_) {
			child->postParentLayout(eng, dimensions_);
		}

		// need to call this after doing layout, since we need to now what the computed padding/border values are.
		border_info_.init(dimensions_);
		background_info_.init(dimensions_);

		if(isBlockBox() && !isFloat()) {
			point p;
			p.y = getTop() + getHeight() + getMBPBottom();
			p.x = eng.getXAtPosition(p.y, p.y + getLineHeight());
			eng.setCursor(p);
		}

		precss_content_height_ = dimensions_.content_.height;
		if(isBlockBox() && styles != nullptr) {
			auto css_h = styles->getHeight();
			if(!css_h->isAuto()) {
				setContentHeight(css_h->getLength().compute(containing.content_.height));				
			}
		}

		eng.closeLineBox();
	}
	void InlineBlockBox::handleLayout(LayoutEngine& eng, const Dimensions& containing)
	{
		eng.setCursor(cursor_);

		layoutChildren(eng);
		layoutHeight(containing);

		if(isReplaceable()) {
			NodePtr node = getNode();
			node->setDimensions(rect(0, 0, getWidth() / LayoutEngine::getFixedPointScale(), getHeight() / LayoutEngine::getFixedPointScale()));
		}

		// try and fit the box at cursor, failing that we move the cursor and try again.
		FixedPoint width_at_cursor = eng.getWidthAtPosition(eng.getCursor().y, eng.getCursor().y + getHeight() + getMBPHeight(), containing.content_.width)
			 - eng.getCursor().x + eng.getXAtPosition(eng.getCursor().y, eng.getCursor().y + getHeight() + getMBPHeight());
		if(getWidth() + getMBPWidth() > width_at_cursor) {
			point p = eng.getCursor();
			p.y += getLineHeight();
			while(eng.hasFloatsAtPosition(p.y, p.y + getHeight() + getMBPHeight()) && getWidth() + getMBPWidth() > width_at_cursor) {
				width_at_cursor = eng.getWidthAtPosition(p.y, p.y + getHeight() + getMBPHeight(), containing.content_.width);
			}
			p.x = eng.getXAtPosition(p.y, p.y + getHeight() + getMBPHeight());
			setContentX(p.x);
			setContentY(p.y);
			p.y += getHeight() + getMBPHeight();
			p.x = eng.getXAtPosition(p.y, p.y + getLineHeight());
			eng.setCursor(p);
		} else {
			setContentX(eng.getCursor().x);
			// XXX if height is greater than other objects on line we need to increase lineheight.
			setContentY(eng.getCursor().y);
			eng.setCursor(point(getLeft() + getWidth() + getMBPRight(), eng.getCursor().y));
		}
	}
Esempio n. 10
0
	void ListItemBox::handleLayout(LayoutEngine& eng, const Dimensions& containing) 
	{
		auto lst = getStyleNode()->getListStyleType();
		switch(lst) {
			case ListStyleType::DISC: /* is the default */ break;
			case ListStyleType::CIRCLE:
				marker_ = utils::codepoint_to_utf8(marker_circle);
				break;
			case ListStyleType::SQUARE:
				marker_ = utils::codepoint_to_utf8(marker_square);
				break;
			case ListStyleType::DECIMAL: {
				std::ostringstream ss;
				ss << std::dec << count_ << ".";
				marker_ = ss.str();
				break;
			}
			case ListStyleType::DECIMAL_LEADING_ZERO: {
				std::ostringstream ss;
				ss << std::dec << std::setfill('0') << std::setw(2) << count_ << ".";
				marker_ = ss.str();
				break;
			}
			case ListStyleType::LOWER_ROMAN:
				if(count_ < 4000) {
					marker_ = to_roman(count_, true) + ".";
				}
				break;
			case ListStyleType::UPPER_ROMAN:
				if(count_ < 4000) {
					marker_ = to_roman(count_, false) + ".";
				}
				break;
			case ListStyleType::LOWER_GREEK:
				if(count_ <= (marker_lower_greek_end - marker_lower_greek + 1)) {
					marker_ = utils::codepoint_to_utf8(marker_lower_greek + count_) + ".";
				}
				break;
			case ListStyleType::LOWER_ALPHA:
			case ListStyleType::LOWER_LATIN:
				if(count_ <= (marker_lower_latin_end - marker_lower_latin + 1)) {
					marker_ = utils::codepoint_to_utf8(marker_lower_latin + count_) + ".";
				}
				break;
			case ListStyleType::UPPER_ALPHA:
			case ListStyleType::UPPER_LATIN:
				if(count_ <= (marker_upper_latin_end - marker_upper_latin + 1)) {
					marker_ = utils::codepoint_to_utf8(marker_upper_latin + count_) + ".";
				}
				break;
			case ListStyleType::ARMENIAN:
				if(count_ <= (marker_armenian_end - marker_armenian + 1)) {
					marker_ = utils::codepoint_to_utf8(marker_armenian + count_) + ".";
				}
				break;
			case ListStyleType::GEORGIAN:
				if(count_ <= (marker_georgian_end - marker_georgian + 1)) {
					marker_ = utils::codepoint_to_utf8(marker_georgian + count_) + ".";
				}
				break;
			case ListStyleType::NONE:
			default: 
				marker_.clear();
				break;
		}

		FixedPoint top = getMBPTop() + containing.content_.height;
		FixedPoint left = getMBPLeft();

		if(isFloat()) {
			// XXX fixme to use a more intelligent approach than iterating every pixel!
			const FixedPoint lh = 65536;//getDimensions().content_.height;
			const FixedPoint box_w = getDimensions().content_.width;

			FixedPoint y = getMBPTop();
			FixedPoint x = getMBPLeft();

			FixedPoint y1 = y + getOffset().y;
			left = getStyleNode()->getFloat() == Float::LEFT ? eng.getXAtPosition(y1, y1 + lh) + x : eng.getX2AtPosition(y1, y1 + lh);
			FixedPoint w = eng.getWidthAtPosition(y1, y1 + lh, containing.content_.width);
			bool placed = false;
			while(!placed) {
				if(w >= box_w) {
					left = left - (getStyleNode()->getFloat() == Float::LEFT ? x : box_w);
					top = y;
					placed = true;
				} else {
					y += lh;
					y1 = y + getOffset().y;
					left = getStyleNode()->getFloat() == Float::LEFT ? eng.getXAtPosition(y1, y1 + lh) + x : eng.getX2AtPosition(y1, y1 + lh);
					w = eng.getWidthAtPosition(y1, y1 + lh, containing.content_.width);
				}
			}
		}

		setContentX(left);
		setContentY(top);

		auto& css_height = getStyleNode()->getHeight();
		if(!css_height->isAuto()) {
			FixedPoint h = css_height->getLength().compute(containing.content_.height);
			//if(h > child_height_) {
			//	/* apply overflow properties */
			//}
			setContentHeight(h);
		}

	}